import { CompressedTextureResource } from "@pixi/compressed-textures";
import { BufferResource, settings, TYPES } from "@pixi/core";
import { BASIS_FORMAT_TO_INTERNAL_FORMAT, BASIS_FORMATS, INTERNAL_FORMAT_TO_BASIS_FORMAT, BASIS_FORMATS_ALPHA } from "../Basis.mjs";
import { TranscoderWorker } from "../TranscoderWorker.mjs";
const _BasisParser = class _BasisParser2 {
  /**
   * Runs transcoding and populates imageArray. It will run the transcoding in a web worker
   * if they are available.
   * @private
   */
  static async transcode(arrayBuffer) {
    let resources;
    return typeof Worker < "u" && _BasisParser2.TranscoderWorker.wasmSource ? resources = await _BasisParser2.transcodeAsync(arrayBuffer) : resources = _BasisParser2.transcodeSync(arrayBuffer), resources;
  }
  /**
   * Finds a suitable worker for transcoding and sends a transcoding request
   * @private
   * @async
   */
  static async transcodeAsync(arrayBuffer) {
    !_BasisParser2.defaultRGBAFormat && !_BasisParser2.defaultRGBFormat && _BasisParser2.autoDetectFormats();
    const workerPool = _BasisParser2.workerPool;
    let leastLoad = 268435456, worker = null;
    for (let i = 0, j = workerPool.length; i < j; i++)
      workerPool[i].load < leastLoad && (worker = workerPool[i], leastLoad = worker.load);
    worker || (worker = new TranscoderWorker(), workerPool.push(worker)), await worker.initAsync();
    const response = await worker.transcodeAsync(
      new Uint8Array(arrayBuffer),
      _BasisParser2.defaultRGBAFormat.basisFormat,
      _BasisParser2.defaultRGBFormat.basisFormat
    ), basisFormat = response.basisFormat, imageArray = response.imageArray, fallbackMode = basisFormat > 12;
    let imageResources;
    if (fallbackMode)
      imageResources = imageArray.map(
        (image) => new BufferResource(
          new Uint16Array(image.levelArray[0].levelBuffer.buffer),
          {
            width: image.width,
            height: image.height
          }
        )
      );
    else {
      const format = BASIS_FORMAT_TO_INTERNAL_FORMAT[response.basisFormat];
      imageResources = new Array(imageArray.length);
      for (let i = 0, j = imageArray.length; i < j; i++)
        imageResources[i] = new CompressedTextureResource(null, {
          format,
          width: imageArray[i].width,
          height: imageArray[i].height,
          levelBuffers: imageArray[i].levelArray,
          levels: imageArray[i].levelArray.length
        });
    }
    return imageResources.basisFormat = basisFormat, imageResources;
  }
  /**
   * Runs transcoding on the main thread.
   * @private
   */
  static transcodeSync(arrayBuffer) {
    !_BasisParser2.defaultRGBAFormat && !_BasisParser2.defaultRGBFormat && _BasisParser2.autoDetectFormats();
    const BASIS = _BasisParser2.basisBinding, data = new Uint8Array(arrayBuffer), basisFile = new BASIS.BasisFile(data), imageCount = basisFile.getNumImages(), basisFormat = basisFile.getHasAlpha() ? _BasisParser2.defaultRGBAFormat.basisFormat : _BasisParser2.defaultRGBFormat.basisFormat, basisFallbackFormat = BASIS_FORMATS.cTFRGB565, imageResources = new Array(imageCount);
    let fallbackMode = _BasisParser2.fallbackMode;
    if (!basisFile.startTranscoding())
      return console.error("Basis failed to start transcoding!"), basisFile.close(), basisFile.delete(), null;
    for (let i = 0; i < imageCount; i++) {
      const levels = fallbackMode ? 1 : basisFile.getNumLevels(i), width = basisFile.getImageWidth(i, 0), height = basisFile.getImageHeight(i, 0), alignedWidth = width + 3 & -4, alignedHeight = height + 3 & -4, imageLevels = new Array(levels);
      for (let j = 0; j < levels; j++) {
        const levelWidth = basisFile.getImageWidth(i, j), levelHeight = basisFile.getImageHeight(i, j), byteSize = basisFile.getImageTranscodedSizeInBytes(
          i,
          0,
          fallbackMode ? basisFallbackFormat : basisFormat
        );
        if (imageLevels[j] = {
          levelID: j,
          levelBuffer: new Uint8Array(byteSize),
          levelWidth,
          levelHeight
        }, !basisFile.transcodeImage(
          imageLevels[j].levelBuffer,
          i,
          0,
          fallbackMode ? basisFallbackFormat : basisFormat,
          !1,
          !1
        ))
          if (fallbackMode) {
            console.error(`Basis failed to transcode image ${i}, level 0!`);
            break;
          } else {
            i = -1, fallbackMode = !0, console.warn(`Basis failed to transcode image ${i}, level 0 to a compressed texture format. Retrying to an uncompressed fallback format!`);
            continue;
          }
      }
      let imageResource;
      fallbackMode ? imageResource = new BufferResource(
        new Uint16Array(imageLevels[0].levelBuffer.buffer),
        { width, height }
      ) : imageResource = new CompressedTextureResource(null, {
        format: BASIS_FORMAT_TO_INTERNAL_FORMAT[basisFormat],
        width: alignedWidth,
        height: alignedHeight,
        levelBuffers: imageLevels,
        levels
      }), imageResources[i] = imageResource;
    }
    basisFile.close(), basisFile.delete();
    const transcodedResources = imageResources;
    return transcodedResources.basisFormat = fallbackMode ? basisFallbackFormat : basisFormat, transcodedResources;
  }
  /**
   * Detects the available compressed texture formats on the device.
   * @param extensions - extensions provided by a WebGL context
   * @ignore
   */
  static autoDetectFormats(extensions) {
    if (!extensions) {
      const gl = settings.ADAPTER.createCanvas().getContext("webgl");
      if (!gl) {
        console.error("WebGL not available for BASIS transcoding. Silently failing.");
        return;
      }
      extensions = {
        bptc: gl.getExtension("EXT_texture_compression_bptc"),
        astc: gl.getExtension("WEBGL_compressed_texture_astc"),
        etc: gl.getExtension("WEBGL_compressed_texture_etc"),
        s3tc: gl.getExtension("WEBGL_compressed_texture_s3tc"),
        s3tc_sRGB: gl.getExtension("WEBGL_compressed_texture_s3tc_srgb"),
        /* eslint-disable-line camelcase */
        pvrtc: gl.getExtension("WEBGL_compressed_texture_pvrtc") || gl.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"),
        etc1: gl.getExtension("WEBGL_compressed_texture_etc1"),
        atc: gl.getExtension("WEBGL_compressed_texture_atc")
      };
    }
    const supportedFormats = {};
    for (const key in extensions) {
      const extension = extensions[key];
      extension && Object.assign(supportedFormats, Object.getPrototypeOf(extension));
    }
    for (let i = 0; i < 2; i++) {
      const detectWithAlpha = !!i;
      let internalFormat, basisFormat;
      for (const id in supportedFormats)
        if (internalFormat = supportedFormats[id], basisFormat = INTERNAL_FORMAT_TO_BASIS_FORMAT[internalFormat], basisFormat !== void 0 && (detectWithAlpha && BASIS_FORMATS_ALPHA[basisFormat] || !detectWithAlpha && !BASIS_FORMATS_ALPHA[basisFormat]))
          break;
      internalFormat ? _BasisParser2[detectWithAlpha ? "defaultRGBAFormat" : "defaultRGBFormat"] = {
        textureFormat: internalFormat,
        basisFormat
      } : (_BasisParser2[detectWithAlpha ? "defaultRGBAFormat" : "defaultRGBFormat"] = {
        textureFormat: TYPES.UNSIGNED_SHORT_5_6_5,
        basisFormat: BASIS_FORMATS.cTFRGB565
      }, _BasisParser2.fallbackMode = !0);
    }
  }
  /**
   * Binds the basis_universal transcoder to decompress *.basis files. You must initialize the transcoder library yourself.
   * @example
   * import { BasisParser } from '@pixi/basis';
   *
   * // BASIS() returns a Promise-like object
   * globalThis.BASIS().then((basisLibrary) =>
   * {
   *     // Initialize basis-library; otherwise, transcoded results maybe corrupt!
   *     basisLibrary.initializeBasis();
   *
   *     // Bind BasisParser to the transcoder
   *     BasisParser.bindTranscoder(basisLibrary);
   * });
   * @param basisLibrary - the initialized transcoder library
   * @private
   */
  static bindTranscoder(basisLibrary) {
    _BasisParser2.basisBinding = basisLibrary;
  }
  /**
   * Loads the transcoder source code for use in {@link PIXI.BasisParser.TranscoderWorker}.
   * @private
   * @param jsURL - URL to the javascript basis transcoder
   * @param wasmURL - URL to the wasm basis transcoder
   */
  static loadTranscoder(jsURL, wasmURL) {
    return _BasisParser2.TranscoderWorker.loadTranscoder(jsURL, wasmURL);
  }
  /**
   * Set the transcoder source code directly
   * @private
   * @param jsSource - source for the javascript basis transcoder
   * @param wasmSource - source for the wasm basis transcoder
   */
  static setTranscoder(jsSource, wasmSource) {
    _BasisParser2.TranscoderWorker.setTranscoder(jsSource, wasmSource);
  }
  static get TRANSCODER_WORKER_POOL_LIMIT() {
    return this.workerPool.length || 1;
  }
  static set TRANSCODER_WORKER_POOL_LIMIT(limit) {
    for (let i = this.workerPool.length; i < limit; i++)
      this.workerPool[i] = new TranscoderWorker(), this.workerPool[i].initAsync();
  }
};
_BasisParser.fallbackMode = !1, _BasisParser.workerPool = [], _BasisParser.TranscoderWorker = TranscoderWorker;
let BasisParser = _BasisParser;
export {
  BasisParser
};
//# sourceMappingURL=BasisParser.mjs.map
