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