import { L as Logger, p as Tools, C as Constants } from './index-Cl9U4nB-.esm.js';
import { A as AutoReleaseWorkerPool } from './workerPool-DP4ZCjkC.esm.js';

/* eslint-disable @typescript-eslint/naming-convention */
/**
 * for description see https://www.khronos.org/opengles/sdk/tools/KTX/
 * for file layout see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
 */
class KhronosTextureContainer {
    /**
     * Creates a new KhronosTextureContainer
     * @param data contents of the KTX container file
     * @param facesExpected should be either 1 or 6, based whether a cube texture or or
     */
    constructor(
    /** contents of the KTX container file */
    data, facesExpected) {
        this.data = data;
        /**
         * If the container has been made invalid (eg. constructor failed to correctly load array buffer)
         */
        this.isInvalid = false;
        if (!KhronosTextureContainer.IsValid(data)) {
            this.isInvalid = true;
            Logger.Error("texture missing KTX identifier");
            return;
        }
        // load the reset of the header in native 32 bit uint
        const dataSize = Uint32Array.BYTES_PER_ELEMENT;
        const headerDataView = new DataView(this.data.buffer, this.data.byteOffset + 12, 13 * dataSize);
        const endianness = headerDataView.getUint32(0, true);
        const littleEndian = endianness === 0x04030201;
        this.glType = headerDataView.getUint32(1 * dataSize, littleEndian); // must be 0 for compressed textures
        this.glTypeSize = headerDataView.getUint32(2 * dataSize, littleEndian); // must be 1 for compressed textures
        this.glFormat = headerDataView.getUint32(3 * dataSize, littleEndian); // must be 0 for compressed textures
        this.glInternalFormat = headerDataView.getUint32(4 * dataSize, littleEndian); // the value of arg passed to gl.compressedTexImage2D(,,x,,,,)
        this.glBaseInternalFormat = headerDataView.getUint32(5 * dataSize, littleEndian); // specify GL_RGB, GL_RGBA, GL_ALPHA, etc (un-compressed only)
        this.pixelWidth = headerDataView.getUint32(6 * dataSize, littleEndian); // level 0 value of arg passed to gl.compressedTexImage2D(,,,x,,,)
        this.pixelHeight = headerDataView.getUint32(7 * dataSize, littleEndian); // level 0 value of arg passed to gl.compressedTexImage2D(,,,,x,,)
        this.pixelDepth = headerDataView.getUint32(8 * dataSize, littleEndian); // level 0 value of arg passed to gl.compressedTexImage3D(,,,,,x,,)
        this.numberOfArrayElements = headerDataView.getUint32(9 * dataSize, littleEndian); // used for texture arrays
        this.numberOfFaces = headerDataView.getUint32(10 * dataSize, littleEndian); // used for cubemap textures, should either be 1 or 6
        this.numberOfMipmapLevels = headerDataView.getUint32(11 * dataSize, littleEndian); // number of levels; disregard possibility of 0 for compressed textures
        this.bytesOfKeyValueData = headerDataView.getUint32(12 * dataSize, littleEndian); // the amount of space after the header for meta-data
        // Make sure we have a compressed type.  Not only reduces work, but probably better to let dev know they are not compressing.
        if (this.glType !== 0) {
            Logger.Error("only compressed formats currently supported");
            this.isInvalid = true;
            return;
        }
        else {
            // value of zero is an indication to generate mipmaps @ runtime.  Not usually allowed for compressed, so disregard.
            this.numberOfMipmapLevels = Math.max(1, this.numberOfMipmapLevels);
        }
        if (this.pixelHeight === 0 || this.pixelDepth !== 0) {
            Logger.Error("only 2D textures currently supported");
            this.isInvalid = true;
            return;
        }
        if (this.numberOfArrayElements !== 0) {
            Logger.Error("texture arrays not currently supported");
            this.isInvalid = true;
            return;
        }
        if (this.numberOfFaces !== facesExpected) {
            Logger.Error("number of faces expected" + facesExpected + ", but found " + this.numberOfFaces);
            this.isInvalid = true;
            return;
        }
        // we now have a completely validated file, so could use existence of loadType as success
        // would need to make this more elaborate & adjust checks above to support more than one load type
        this.loadType = KhronosTextureContainer.COMPRESSED_2D;
    }
    /**
     * Uploads KTX content to a Babylon Texture.
     * It is assumed that the texture has already been created & is currently bound
     * @internal
     */
    uploadLevels(texture, loadMipmaps) {
        switch (this.loadType) {
            case KhronosTextureContainer.COMPRESSED_2D:
                this._upload2DCompressedLevels(texture, loadMipmaps);
                break;
        }
    }
    _upload2DCompressedLevels(texture, loadMipmaps) {
        // initialize width & height for level 1
        let dataOffset = KhronosTextureContainer.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.data.buffer, this.data.byteOffset + dataOffset, 1)[0]; // size per face, since not supporting array cubemaps
            dataOffset += 4; //image data starts from next multiple of 4 offset. Each face refers to same imagesize field above.
            for (let face = 0; face < this.numberOfFaces; face++) {
                const byteArray = new Uint8Array(this.data.buffer, this.data.byteOffset + dataOffset, imageSize);
                const engine = texture.getEngine();
                engine._uploadCompressedDataToTextureDirectly(texture, texture.format, width, height, byteArray, face, level);
                dataOffset += imageSize; // add size of the image for the next face/mipmap
                dataOffset += 3 - ((imageSize + 3) % 4); // add padding for odd sized image
            }
            width = Math.max(1.0, width * 0.5);
            height = Math.max(1.0, height * 0.5);
        }
    }
    /**
     * Checks if the given data starts with a KTX file identifier.
     * @param data the data to check
     * @returns true if the data is a KTX file or false otherwise
     */
    static IsValid(data) {
        if (data.byteLength >= 12) {
            // '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n'
            const identifier = new Uint8Array(data.buffer, data.byteOffset, 12);
            if (identifier[0] === 0xab &&
                identifier[1] === 0x4b &&
                identifier[2] === 0x54 &&
                identifier[3] === 0x58 &&
                identifier[4] === 0x20 &&
                identifier[5] === 0x31 &&
                identifier[6] === 0x31 &&
                identifier[7] === 0xbb &&
                identifier[8] === 0x0d &&
                identifier[9] === 0x0a &&
                identifier[10] === 0x1a &&
                identifier[11] === 0x0a) {
                return true;
            }
        }
        return false;
    }
}
KhronosTextureContainer.HEADER_LEN = 12 + 13 * 4; // identifier + header elements (not including key value meta-data pairs)
// load types
KhronosTextureContainer.COMPRESSED_2D = 0; // uses a gl.compressedTexImage2D()
KhronosTextureContainer.COMPRESSED_3D = 1; // uses a gl.compressedTexImage3D()
KhronosTextureContainer.TEX_2D = 2; // uses a gl.texImage2D()
KhronosTextureContainer.TEX_3D = 3; // uses a gl.texImage3D()

var SourceTextureFormat;
(function (SourceTextureFormat) {
    SourceTextureFormat[SourceTextureFormat["ETC1S"] = 0] = "ETC1S";
    // eslint-disable-next-line @typescript-eslint/naming-convention
    SourceTextureFormat[SourceTextureFormat["UASTC4x4"] = 1] = "UASTC4x4";
})(SourceTextureFormat || (SourceTextureFormat = {}));
var TranscodeTarget;
(function (TranscodeTarget) {
    TranscodeTarget[TranscodeTarget["ASTC_4X4_RGBA"] = 0] = "ASTC_4X4_RGBA";
    // eslint-disable-next-line @typescript-eslint/naming-convention
    TranscodeTarget[TranscodeTarget["ASTC_4x4_RGBA"] = 0] = "ASTC_4x4_RGBA";
    TranscodeTarget[TranscodeTarget["BC7_RGBA"] = 1] = "BC7_RGBA";
    TranscodeTarget[TranscodeTarget["BC3_RGBA"] = 2] = "BC3_RGBA";
    TranscodeTarget[TranscodeTarget["BC1_RGB"] = 3] = "BC1_RGB";
    TranscodeTarget[TranscodeTarget["PVRTC1_4_RGBA"] = 4] = "PVRTC1_4_RGBA";
    TranscodeTarget[TranscodeTarget["PVRTC1_4_RGB"] = 5] = "PVRTC1_4_RGB";
    TranscodeTarget[TranscodeTarget["ETC2_RGBA"] = 6] = "ETC2_RGBA";
    TranscodeTarget[TranscodeTarget["ETC1_RGB"] = 7] = "ETC1_RGB";
    TranscodeTarget[TranscodeTarget["RGBA32"] = 8] = "RGBA32";
    TranscodeTarget[TranscodeTarget["R8"] = 9] = "R8";
    TranscodeTarget[TranscodeTarget["RG8"] = 10] = "RG8";
})(TranscodeTarget || (TranscodeTarget = {}));
var EngineFormat;
(function (EngineFormat) {
    EngineFormat[EngineFormat["COMPRESSED_RGBA_BPTC_UNORM_EXT"] = 36492] = "COMPRESSED_RGBA_BPTC_UNORM_EXT";
    EngineFormat[EngineFormat["COMPRESSED_RGBA_ASTC_4X4_KHR"] = 37808] = "COMPRESSED_RGBA_ASTC_4X4_KHR";
    EngineFormat[EngineFormat["COMPRESSED_RGB_S3TC_DXT1_EXT"] = 33776] = "COMPRESSED_RGB_S3TC_DXT1_EXT";
    EngineFormat[EngineFormat["COMPRESSED_RGBA_S3TC_DXT5_EXT"] = 33779] = "COMPRESSED_RGBA_S3TC_DXT5_EXT";
    EngineFormat[EngineFormat["COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"] = 35842] = "COMPRESSED_RGBA_PVRTC_4BPPV1_IMG";
    EngineFormat[EngineFormat["COMPRESSED_RGB_PVRTC_4BPPV1_IMG"] = 35840] = "COMPRESSED_RGB_PVRTC_4BPPV1_IMG";
    EngineFormat[EngineFormat["COMPRESSED_RGBA8_ETC2_EAC"] = 37496] = "COMPRESSED_RGBA8_ETC2_EAC";
    EngineFormat[EngineFormat["COMPRESSED_RGB8_ETC2"] = 37492] = "COMPRESSED_RGB8_ETC2";
    EngineFormat[EngineFormat["COMPRESSED_RGB_ETC1_WEBGL"] = 36196] = "COMPRESSED_RGB_ETC1_WEBGL";
    EngineFormat[EngineFormat["RGBA8Format"] = 32856] = "RGBA8Format";
    EngineFormat[EngineFormat["R8Format"] = 33321] = "R8Format";
    // eslint-disable-next-line @typescript-eslint/naming-convention
    EngineFormat[EngineFormat["RG8Format"] = 33323] = "RG8Format";
})(EngineFormat || (EngineFormat = {}));

function applyConfig(urls, binariesAndModulesContainer) {
    const KTX2DecoderModule = binariesAndModulesContainer?.jsDecoderModule || KTX2DECODER;
    if (urls) {
        if (urls.wasmBaseUrl) {
            KTX2DecoderModule.Transcoder.WasmBaseUrl = urls.wasmBaseUrl;
        }
        if (urls.wasmUASTCToASTC) {
            KTX2DecoderModule.LiteTranscoder_UASTC_ASTC.WasmModuleURL = urls.wasmUASTCToASTC;
        }
        if (urls.wasmUASTCToBC7) {
            KTX2DecoderModule.LiteTranscoder_UASTC_BC7.WasmModuleURL = urls.wasmUASTCToBC7;
        }
        if (urls.wasmUASTCToRGBA_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RGBA_UNORM.WasmModuleURL = urls.wasmUASTCToRGBA_UNORM;
        }
        if (urls.wasmUASTCToRGBA_SRGB) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RGBA_SRGB.WasmModuleURL = urls.wasmUASTCToRGBA_SRGB;
        }
        if (urls.wasmUASTCToR8_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_R8_UNORM.WasmModuleURL = urls.wasmUASTCToR8_UNORM;
        }
        if (urls.wasmUASTCToRG8_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RG8_UNORM.WasmModuleURL = urls.wasmUASTCToRG8_UNORM;
        }
        if (urls.jsMSCTranscoder) {
            KTX2DecoderModule.MSCTranscoder.JSModuleURL = urls.jsMSCTranscoder;
        }
        if (urls.wasmMSCTranscoder) {
            KTX2DecoderModule.MSCTranscoder.WasmModuleURL = urls.wasmMSCTranscoder;
        }
        if (urls.wasmZSTDDecoder) {
            KTX2DecoderModule.ZSTDDecoder.WasmModuleURL = urls.wasmZSTDDecoder;
        }
    }
    if (binariesAndModulesContainer) {
        if (binariesAndModulesContainer.wasmUASTCToASTC) {
            KTX2DecoderModule.LiteTranscoder_UASTC_ASTC.WasmBinary = binariesAndModulesContainer.wasmUASTCToASTC;
        }
        if (binariesAndModulesContainer.wasmUASTCToBC7) {
            KTX2DecoderModule.LiteTranscoder_UASTC_BC7.WasmBinary = binariesAndModulesContainer.wasmUASTCToBC7;
        }
        if (binariesAndModulesContainer.wasmUASTCToRGBA_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RGBA_UNORM.WasmBinary = binariesAndModulesContainer.wasmUASTCToRGBA_UNORM;
        }
        if (binariesAndModulesContainer.wasmUASTCToRGBA_SRGB) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RGBA_SRGB.WasmBinary = binariesAndModulesContainer.wasmUASTCToRGBA_SRGB;
        }
        if (binariesAndModulesContainer.wasmUASTCToR8_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_R8_UNORM.WasmBinary = binariesAndModulesContainer.wasmUASTCToR8_UNORM;
        }
        if (binariesAndModulesContainer.wasmUASTCToRG8_UNORM) {
            KTX2DecoderModule.LiteTranscoder_UASTC_RG8_UNORM.WasmBinary = binariesAndModulesContainer.wasmUASTCToRG8_UNORM;
        }
        if (binariesAndModulesContainer.jsMSCTranscoder) {
            KTX2DecoderModule.MSCTranscoder.JSModule = binariesAndModulesContainer.jsMSCTranscoder;
        }
        if (binariesAndModulesContainer.wasmMSCTranscoder) {
            KTX2DecoderModule.MSCTranscoder.WasmBinary = binariesAndModulesContainer.wasmMSCTranscoder;
        }
        if (binariesAndModulesContainer.wasmZSTDDecoder) {
            KTX2DecoderModule.ZSTDDecoder.WasmBinary = binariesAndModulesContainer.wasmZSTDDecoder;
        }
    }
}
function workerFunction(KTX2DecoderModule) {
    if (typeof KTX2DecoderModule === "undefined" && typeof KTX2DECODER !== "undefined") {
        KTX2DecoderModule = KTX2DECODER;
    }
    let ktx2Decoder;
    onmessage = (event) => {
        if (!event.data) {
            return;
        }
        switch (event.data.action) {
            case "init": {
                const urls = event.data.urls;
                if (urls) {
                    if (urls.jsDecoderModule && typeof KTX2DecoderModule === "undefined") {
                        importScripts(urls.jsDecoderModule);
                        // assuming global namespace populated by the script (UMD pattern)
                        KTX2DecoderModule = KTX2DECODER;
                    }
                    applyConfig(urls);
                }
                if (event.data.wasmBinaries) {
                    applyConfig(undefined, { ...event.data.wasmBinaries, jsDecoderModule: KTX2DecoderModule });
                }
                ktx2Decoder = new KTX2DecoderModule.KTX2Decoder();
                postMessage({ action: "init" });
                break;
            }
            case "setDefaultDecoderOptions": {
                KTX2DecoderModule.KTX2Decoder.DefaultDecoderOptions = event.data.options;
                break;
            }
            case "decode":
                ktx2Decoder
                    .decode(event.data.data, event.data.caps, event.data.options)
                    // eslint-disable-next-line github/no-then
                    .then((data) => {
                    const buffers = [];
                    for (let mip = 0; mip < data.mipmaps.length; ++mip) {
                        const mipmap = data.mipmaps[mip];
                        if (mipmap && mipmap.data) {
                            buffers.push(mipmap.data.buffer);
                        }
                    }
                    postMessage({ action: "decoded", success: true, decodedData: data }, buffers);
                })
                    // eslint-disable-next-line github/no-then
                    .catch((reason) => {
                    postMessage({ action: "decoded", success: false, msg: reason });
                });
                break;
        }
    };
}
async function initializeWebWorker(worker, wasmBinaries, urls) {
    return await new Promise((resolve, reject) => {
        const onError = (error) => {
            worker.removeEventListener("error", onError);
            worker.removeEventListener("message", onMessage);
            // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
            reject(error);
        };
        const onMessage = (message) => {
            if (message.data.action === "init") {
                worker.removeEventListener("error", onError);
                worker.removeEventListener("message", onMessage);
                resolve(worker);
            }
        };
        worker.addEventListener("error", onError);
        worker.addEventListener("message", onMessage);
        worker.postMessage({
            action: "init",
            urls,
            wasmBinaries,
        });
    });
}

/**
 * Class that defines the default KTX2 decoder options.
 *
 * This class is useful for providing options to the KTX2 decoder to control how the source data is transcoded.
 */
class DefaultKTX2DecoderOptions {
    constructor() {
        this._isDirty = true;
        this._useRGBAIfOnlyBC1BC3AvailableWhenUASTC = true;
        this._ktx2DecoderOptions = {};
    }
    /**
     * Gets the dirty flag
     */
    get isDirty() {
        return this._isDirty;
    }
    /**
     * force a (uncompressed) RGBA transcoded format if transcoding a UASTC source format and ASTC + BC7 are not available as a compressed transcoded format
     */
    get useRGBAIfASTCBC7NotAvailableWhenUASTC() {
        return this._useRGBAIfASTCBC7NotAvailableWhenUASTC;
    }
    set useRGBAIfASTCBC7NotAvailableWhenUASTC(value) {
        if (this._useRGBAIfASTCBC7NotAvailableWhenUASTC === value) {
            return;
        }
        this._useRGBAIfASTCBC7NotAvailableWhenUASTC = value;
        this._isDirty = true;
    }
    /**
     * force a (uncompressed) RGBA transcoded format if transcoding a UASTC source format and only BC1 or BC3 are available as a compressed transcoded format.
     * This property is true by default to favor speed over memory, because currently transcoding from UASTC to BC1/3 is slow because the transcoder transcodes
     * to uncompressed and then recompresses the texture
     */
    get useRGBAIfOnlyBC1BC3AvailableWhenUASTC() {
        return this._useRGBAIfOnlyBC1BC3AvailableWhenUASTC;
    }
    set useRGBAIfOnlyBC1BC3AvailableWhenUASTC(value) {
        if (this._useRGBAIfOnlyBC1BC3AvailableWhenUASTC === value) {
            return;
        }
        this._useRGBAIfOnlyBC1BC3AvailableWhenUASTC = value;
        this._isDirty = true;
    }
    /**
     * force to always use (uncompressed) RGBA for transcoded format
     */
    get forceRGBA() {
        return this._forceRGBA;
    }
    set forceRGBA(value) {
        if (this._forceRGBA === value) {
            return;
        }
        this._forceRGBA = value;
        this._isDirty = true;
    }
    /**
     * force to always use (uncompressed) R8 for transcoded format
     */
    get forceR8() {
        return this._forceR8;
    }
    set forceR8(value) {
        if (this._forceR8 === value) {
            return;
        }
        this._forceR8 = value;
        this._isDirty = true;
    }
    /**
     * force to always use (uncompressed) RG8 for transcoded format
     */
    get forceRG8() {
        return this._forceRG8;
    }
    set forceRG8(value) {
        if (this._forceRG8 === value) {
            return;
        }
        this._forceRG8 = value;
        this._isDirty = true;
    }
    /**
     * list of transcoders to bypass when looking for a suitable transcoder. The available transcoders are:
     *      UniversalTranscoder_UASTC_ASTC
     *      UniversalTranscoder_UASTC_BC7
     *      UniversalTranscoder_UASTC_RGBA_UNORM
     *      UniversalTranscoder_UASTC_RGBA_SRGB
     *      UniversalTranscoder_UASTC_R8_UNORM
     *      UniversalTranscoder_UASTC_RG8_UNORM
     *      MSCTranscoder
     */
    get bypassTranscoders() {
        return this._bypassTranscoders;
    }
    set bypassTranscoders(value) {
        if (this._bypassTranscoders === value) {
            return;
        }
        this._bypassTranscoders = value;
        this._isDirty = true;
    }
    /** @internal */
    _getKTX2DecoderOptions() {
        if (!this._isDirty) {
            return this._ktx2DecoderOptions;
        }
        this._isDirty = false;
        const options = {};
        if (this._useRGBAIfASTCBC7NotAvailableWhenUASTC !== undefined) {
            options.useRGBAIfASTCBC7NotAvailableWhenUASTC = this._useRGBAIfASTCBC7NotAvailableWhenUASTC;
        }
        if (this._forceRGBA !== undefined) {
            options.forceRGBA = this._forceRGBA;
        }
        if (this._forceR8 !== undefined) {
            options.forceR8 = this._forceR8;
        }
        if (this._forceRG8 !== undefined) {
            options.forceRG8 = this._forceRG8;
        }
        if (this._bypassTranscoders !== undefined) {
            options.bypassTranscoders = this._bypassTranscoders;
        }
        if (this.useRGBAIfOnlyBC1BC3AvailableWhenUASTC) {
            options.transcodeFormatDecisionTree = {
                UASTC: {
                    transcodeFormat: [TranscodeTarget.BC1_RGB, TranscodeTarget.BC3_RGBA],
                    yes: {
                        transcodeFormat: TranscodeTarget.RGBA32,
                        engineFormat: 32856 /* EngineFormat.RGBA8Format */,
                        roundToMultiple4: false,
                    },
                },
            };
        }
        this._ktx2DecoderOptions = options;
        return options;
    }
}
/**
 * Class for loading KTX2 files
 */
class KhronosTextureContainer2 {
    static GetDefaultNumWorkers() {
        if (typeof navigator !== "object" || !navigator.hardwareConcurrency) {
            return 1;
        }
        // Use 50% of the available logical processors but capped at 4.
        return Math.min(Math.floor(navigator.hardwareConcurrency * 0.5), 4);
    }
    static _Initialize(numWorkers) {
        if (KhronosTextureContainer2._WorkerPoolPromise || KhronosTextureContainer2._DecoderModulePromise) {
            return;
        }
        const urls = {
            wasmBaseUrl: Tools.ScriptBaseUrl,
            jsDecoderModule: Tools.GetBabylonScriptURL(this.URLConfig.jsDecoderModule, true),
            wasmUASTCToASTC: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToASTC, true),
            wasmUASTCToBC7: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToBC7, true),
            wasmUASTCToRGBA_UNORM: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToRGBA_UNORM, true),
            wasmUASTCToRGBA_SRGB: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToRGBA_SRGB, true),
            wasmUASTCToR8_UNORM: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToR8_UNORM, true),
            wasmUASTCToRG8_UNORM: Tools.GetBabylonScriptURL(this.URLConfig.wasmUASTCToRG8_UNORM, true),
            jsMSCTranscoder: Tools.GetBabylonScriptURL(this.URLConfig.jsMSCTranscoder, true),
            wasmMSCTranscoder: Tools.GetBabylonScriptURL(this.URLConfig.wasmMSCTranscoder, true),
            wasmZSTDDecoder: Tools.GetBabylonScriptURL(this.URLConfig.wasmZSTDDecoder, true),
        };
        if (numWorkers && typeof Worker === "function" && typeof URL !== "undefined") {
            KhronosTextureContainer2._WorkerPoolPromise = new Promise((resolve) => {
                // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
                const workerContent = `${applyConfig}(${workerFunction})()`;
                const workerBlobUrl = URL.createObjectURL(new Blob([workerContent], { type: "application/javascript" }));
                resolve(new AutoReleaseWorkerPool(numWorkers, async () => await initializeWebWorker(new Worker(workerBlobUrl), undefined, urls)));
            });
        }
        else {
            if (typeof KhronosTextureContainer2._KTX2DecoderModule === "undefined") {
                // eslint-disable-next-line github/no-then
                KhronosTextureContainer2._DecoderModulePromise = Tools.LoadBabylonScriptAsync(urls.jsDecoderModule).then(() => {
                    KhronosTextureContainer2._KTX2DecoderModule = KTX2DECODER;
                    KhronosTextureContainer2._KTX2DecoderModule.MSCTranscoder.UseFromWorkerThread = false;
                    KhronosTextureContainer2._KTX2DecoderModule.WASMMemoryManager.LoadBinariesFromCurrentThread = true;
                    applyConfig(urls, KhronosTextureContainer2._KTX2DecoderModule);
                    // eslint-disable-next-line @typescript-eslint/no-unsafe-return
                    return new KhronosTextureContainer2._KTX2DecoderModule.KTX2Decoder();
                });
            }
            else {
                KhronosTextureContainer2._KTX2DecoderModule.MSCTranscoder.UseFromWorkerThread = false;
                KhronosTextureContainer2._KTX2DecoderModule.WASMMemoryManager.LoadBinariesFromCurrentThread = true;
                KhronosTextureContainer2._DecoderModulePromise = Promise.resolve(new KhronosTextureContainer2._KTX2DecoderModule.KTX2Decoder());
            }
        }
    }
    /**
     * Constructor
     * @param engine The engine to use
     * @param numWorkersOrOptions The number of workers for async operations. Specify `0` to disable web workers and run synchronously in the current context.
     */
    constructor(engine, numWorkersOrOptions = KhronosTextureContainer2.DefaultNumWorkers) {
        this._engine = engine;
        const workerPoolOption = (typeof numWorkersOrOptions === "object" && numWorkersOrOptions.workerPool) || KhronosTextureContainer2.WorkerPool;
        if (workerPoolOption) {
            KhronosTextureContainer2._WorkerPoolPromise = Promise.resolve(workerPoolOption);
        }
        else {
            // set the KTX2 decoder module
            if (typeof numWorkersOrOptions === "object") {
                KhronosTextureContainer2._KTX2DecoderModule = numWorkersOrOptions?.binariesAndModulesContainer?.jsDecoderModule;
            }
            else if (typeof KTX2DECODER !== "undefined") {
                KhronosTextureContainer2._KTX2DecoderModule = KTX2DECODER;
            }
            const numberOfWorkers = typeof numWorkersOrOptions === "number" ? numWorkersOrOptions : (numWorkersOrOptions.numWorkers ?? KhronosTextureContainer2.DefaultNumWorkers);
            KhronosTextureContainer2._Initialize(numberOfWorkers);
        }
    }
    /**
     * @internal
     */
    async _uploadAsync(data, internalTexture, options) {
        const caps = this._engine.getCaps();
        const compressedTexturesCaps = {
            astc: !!caps.astc,
            bptc: !!caps.bptc,
            s3tc: !!caps.s3tc,
            pvrtc: !!caps.pvrtc,
            etc2: !!caps.etc2,
            etc1: !!caps.etc1,
        };
        if (KhronosTextureContainer2._WorkerPoolPromise) {
            const workerPool = await KhronosTextureContainer2._WorkerPoolPromise;
            return await new Promise((resolve, reject) => {
                workerPool.push((worker, onComplete) => {
                    const onError = (error) => {
                        worker.removeEventListener("error", onError);
                        worker.removeEventListener("message", onMessage);
                        // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
                        reject(error);
                        onComplete();
                    };
                    const onMessage = (message) => {
                        if (message.data.action === "decoded") {
                            worker.removeEventListener("error", onError);
                            worker.removeEventListener("message", onMessage);
                            if (!message.data.success) {
                                // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
                                reject({ message: message.data.msg });
                            }
                            else {
                                try {
                                    this._createTexture(message.data.decodedData, internalTexture, options);
                                    resolve();
                                }
                                catch (err) {
                                    // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
                                    reject({ message: err });
                                }
                            }
                            onComplete();
                        }
                    };
                    worker.addEventListener("error", onError);
                    worker.addEventListener("message", onMessage);
                    worker.postMessage({ action: "setDefaultDecoderOptions", options: KhronosTextureContainer2.DefaultDecoderOptions._getKTX2DecoderOptions() });
                    const dataCopy = new Uint8Array(data.byteLength);
                    dataCopy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
                    worker.postMessage({ action: "decode", data: dataCopy, caps: compressedTexturesCaps, options }, [dataCopy.buffer]);
                });
            });
        }
        else if (KhronosTextureContainer2._DecoderModulePromise) {
            const decoder = await KhronosTextureContainer2._DecoderModulePromise;
            if (KhronosTextureContainer2.DefaultDecoderOptions.isDirty) {
                KhronosTextureContainer2._KTX2DecoderModule.KTX2Decoder.DefaultDecoderOptions = KhronosTextureContainer2.DefaultDecoderOptions._getKTX2DecoderOptions();
            }
            return await new Promise((resolve, reject) => {
                decoder
                    .decode(data, caps)
                    // eslint-disable-next-line github/no-then
                    .then((data) => {
                    this._createTexture(data, internalTexture);
                    resolve();
                })
                    // eslint-disable-next-line github/no-then
                    .catch((reason) => {
                    // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
                    reject({ message: reason });
                });
            });
        }
        throw new Error("KTX2 decoder module is not available");
    }
    _createTexture(data, internalTexture, options) {
        const oglTexture2D = 3553; // gl.TEXTURE_2D
        this._engine._bindTextureDirectly(oglTexture2D, internalTexture);
        if (options) {
            // return back some information about the decoded data
            options.transcodedFormat = data.transcodedFormat;
            options.isInGammaSpace = data.isInGammaSpace;
            options.hasAlpha = data.hasAlpha;
            options.transcoderName = data.transcoderName;
        }
        let isUncompressedFormat = true;
        switch (data.transcodedFormat) {
            case 0x8058 /* RGBA8 */:
                internalTexture.type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
                internalTexture.format = Constants.TEXTUREFORMAT_RGBA;
                break;
            case 0x8229 /* R8 */:
                internalTexture.type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
                internalTexture.format = Constants.TEXTUREFORMAT_R;
                break;
            case 0x822b /* RG8 */:
                internalTexture.type = Constants.TEXTURETYPE_UNSIGNED_BYTE;
                internalTexture.format = Constants.TEXTUREFORMAT_RG;
                break;
            default:
                internalTexture.format = data.transcodedFormat;
                isUncompressedFormat = false;
                break;
        }
        internalTexture._gammaSpace = data.isInGammaSpace;
        internalTexture.generateMipMaps = data.mipmaps.length > 1;
        internalTexture.width = data.mipmaps[0].width;
        internalTexture.height = data.mipmaps[0].height;
        if (data.errors) {
            throw new Error("KTX2 container - could not transcode the data. " + data.errors);
        }
        for (let t = 0; t < data.mipmaps.length; ++t) {
            const mipmap = data.mipmaps[t];
            if (!mipmap || !mipmap.data) {
                throw new Error("KTX2 container - could not transcode one of the image");
            }
            if (isUncompressedFormat) {
                // uncompressed RGBA / R8 / RG8
                internalTexture.width = mipmap.width; // need to set width/height so that the call to _uploadDataToTextureDirectly uses the right dimensions
                internalTexture.height = mipmap.height;
                this._engine._uploadDataToTextureDirectly(internalTexture, mipmap.data, 0, t, undefined, true);
            }
            else {
                this._engine._uploadCompressedDataToTextureDirectly(internalTexture, data.transcodedFormat, mipmap.width, mipmap.height, mipmap.data, 0, t);
            }
        }
        internalTexture._extension = ".ktx2";
        internalTexture.isReady = true;
        this._engine._bindTextureDirectly(oglTexture2D, null);
    }
    /**
     * Checks if the given data starts with a KTX2 file identifier.
     * @param data the data to check
     * @returns true if the data is a KTX2 file or false otherwise
     */
    static IsValid(data) {
        if (data.byteLength >= 12) {
            // '«', 'K', 'T', 'X', ' ', '2', '0', '»', '\r', '\n', '\x1A', '\n'
            const identifier = new Uint8Array(data.buffer, data.byteOffset, 12);
            if (identifier[0] === 0xab &&
                identifier[1] === 0x4b &&
                identifier[2] === 0x54 &&
                identifier[3] === 0x58 &&
                identifier[4] === 0x20 &&
                identifier[5] === 0x32 &&
                identifier[6] === 0x30 &&
                identifier[7] === 0xbb &&
                identifier[8] === 0x0d &&
                identifier[9] === 0x0a &&
                identifier[10] === 0x1a &&
                identifier[11] === 0x0a) {
                return true;
            }
        }
        return false;
    }
}
/**
 * URLs to use when loading the KTX2 decoder module as well as its dependencies
 * If a url is null, the default url is used (pointing to https://preview.babylonjs.com)
 * Note that jsDecoderModule can't be null and that the other dependencies will only be loaded if necessary
 * Urls you can change:
 *     URLConfig.jsDecoderModule
 *     URLConfig.wasmUASTCToASTC
 *     URLConfig.wasmUASTCToBC7
 *     URLConfig.wasmUASTCToRGBA_UNORM
 *     URLConfig.wasmUASTCToRGBA_SRGB
 *     URLConfig.wasmUASTCToR8_UNORM
 *     URLConfig.wasmUASTCToRG8_UNORM
 *     URLConfig.jsMSCTranscoder
 *     URLConfig.wasmMSCTranscoder
 *     URLConfig.wasmZSTDDecoder
 * You can see their default values in this PG: https://playground.babylonjs.com/#EIJH8L#29
 */
KhronosTextureContainer2.URLConfig = {
    jsDecoderModule: "https://cdn.babylonjs.com/babylon.ktx2Decoder.js",
    wasmUASTCToASTC: null,
    wasmUASTCToBC7: null,
    wasmUASTCToRGBA_UNORM: null,
    wasmUASTCToRGBA_SRGB: null,
    wasmUASTCToR8_UNORM: null,
    wasmUASTCToRG8_UNORM: null,
    jsMSCTranscoder: null,
    wasmMSCTranscoder: null,
    wasmZSTDDecoder: null,
};
/**
 * Default number of workers used to handle data decoding
 */
KhronosTextureContainer2.DefaultNumWorkers = KhronosTextureContainer2.GetDefaultNumWorkers();
/**
 * Default configuration for the KTX2 decoder.
 * The options defined in this way have priority over those passed when creating a KTX2 texture with new Texture(...).
 */
KhronosTextureContainer2.DefaultDecoderOptions = new DefaultKTX2DecoderOptions();

function MapSRGBToLinear(format) {
    switch (format) {
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB_S3TC_DXT1_EXT:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGB_S3TC_DXT1;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGBA_S3TC_DXT3;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGBA_S3TC_DXT5;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB8_ETC2:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGB8_ETC2;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGBA8_ETC2_EAC;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGBA_ASTC_4x4;
        case Constants.TEXTUREFORMAT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
            return Constants.TEXTUREFORMAT_COMPRESSED_RGBA_BPTC_UNORM;
    }
    return null;
}
/**
 * Implementation of the KTX Texture Loader.
 * @internal
 */
// eslint-disable-next-line @typescript-eslint/naming-convention
class _KTXTextureLoader {
    constructor() {
        /**
         * Defines whether the loader supports cascade loading the different faces.
         */
        this.supportCascades = false;
    }
    /**
     * Uploads the cube texture data to the WebGL texture. It has already been bound.
     * @param data contains the texture data
     * @param texture defines the BabylonJS internal texture
     * @param createPolynomials will be true if polynomials have been requested
     * @param onLoad defines the callback to trigger once the texture is ready
     */
    loadCubeData(data, texture, createPolynomials, onLoad) {
        if (Array.isArray(data)) {
            return;
        }
        // Need to invert vScale as invertY via UNPACK_FLIP_Y_WEBGL is not supported by compressed texture
        texture._invertVScale = !texture.invertY;
        const engine = texture.getEngine();
        const ktx = new KhronosTextureContainer(data, 6);
        const loadMipmap = ktx.numberOfMipmapLevels > 1 && texture.generateMipMaps;
        engine._unpackFlipY(true);
        ktx.uploadLevels(texture, texture.generateMipMaps);
        texture.width = ktx.pixelWidth;
        texture.height = ktx.pixelHeight;
        engine._setCubeMapTextureParams(texture, loadMipmap, ktx.numberOfMipmapLevels - 1);
        texture.isReady = true;
        texture.onLoadedObservable.notifyObservers(texture);
        texture.onLoadedObservable.clear();
        if (onLoad) {
            onLoad();
        }
    }
    /**
     * Uploads the 2D texture data to the WebGL texture. It has already been bound once in the callback.
     * @param data contains the texture data
     * @param texture defines the BabylonJS internal texture
     * @param callback defines the method to call once ready to upload
     * @param options
     */
    loadData(data, texture, callback, options) {
        if (KhronosTextureContainer.IsValid(data)) {
            // Need to invert vScale as invertY via UNPACK_FLIP_Y_WEBGL is not supported by compressed texture
            texture._invertVScale = !texture.invertY;
            const ktx = new KhronosTextureContainer(data, 1);
            const mappedFormat = MapSRGBToLinear(ktx.glInternalFormat);
            if (mappedFormat) {
                texture.format = mappedFormat;
                texture._useSRGBBuffer = texture.getEngine()._getUseSRGBBuffer(true, texture.generateMipMaps);
                texture._gammaSpace = true;
            }
            else {
                texture.format = ktx.glInternalFormat;
            }
            callback(ktx.pixelWidth, ktx.pixelHeight, texture.generateMipMaps, true, () => {
                ktx.uploadLevels(texture, texture.generateMipMaps);
            }, ktx.isInvalid);
        }
        else if (KhronosTextureContainer2.IsValid(data)) {
            const ktx2 = new KhronosTextureContainer2(texture.getEngine());
            // eslint-disable-next-line github/no-then
            ktx2._uploadAsync(data, texture, options).then(() => {
                callback(texture.width, texture.height, texture.generateMipMaps, true, () => { }, false);
            }, (error) => {
                Logger.Warn(`Failed to load KTX2 texture data: ${error.message}`);
                callback(0, 0, false, false, () => { }, true);
            });
        }
        else {
            Logger.Error("texture missing KTX identifier");
            callback(0, 0, false, false, () => { }, true);
        }
    }
}

export { _KTXTextureLoader };
//# sourceMappingURL=ktxTextureLoader-DiAHutKO.esm.js.map
