| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 | ( function () {	/** * THREE.Loader for Basis Universal GPU Texture Codec. * * Basis Universal is a "supercompressed" GPU texture and texture video * compression system that outputs a highly compressed intermediate file format * (.basis) that can be quickly transcoded to a wide variety of GPU texture * compression formats. * * This loader parallelizes the transcoding process across a configurable number * of web workers, before transferring the transcoded compressed texture back * to the main thread. */	const _taskCache = new WeakMap();	class BasisTextureLoader extends THREE.Loader {		constructor( manager ) {			super( manager );			this.transcoderPath = '';			this.transcoderBinary = null;			this.transcoderPending = null;			this.workerLimit = 4;			this.workerPool = [];			this.workerNextTaskID = 1;			this.workerSourceURL = '';			this.workerConfig = null;		}		setTranscoderPath( path ) {			this.transcoderPath = path;			return this;		}		setWorkerLimit( workerLimit ) {			this.workerLimit = workerLimit;			return this;		}		detectSupport( renderer ) {			this.workerConfig = {				astcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ),				etc1Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc1' ),				etc2Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc' ),				dxtSupported: renderer.extensions.has( 'WEBGL_compressed_texture_s3tc' ),				bptcSupported: renderer.extensions.has( 'EXT_texture_compression_bptc' ),				pvrtcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_pvrtc' ) || renderer.extensions.has( 'WEBKIT_WEBGL_compressed_texture_pvrtc' )			};			return this;		}		load( url, onLoad, onProgress, onError ) {			const loader = new THREE.FileLoader( this.manager );			loader.setResponseType( 'arraybuffer' );			loader.setWithCredentials( this.withCredentials );			const texture = new THREE.CompressedTexture();			loader.load( url, buffer => {				// Check for an existing task using this buffer. A transferred buffer cannot be transferred				// again from this thread.				if ( _taskCache.has( buffer ) ) {					const cachedTask = _taskCache.get( buffer );					return cachedTask.promise.then( onLoad ).catch( onError );				}				this._createTexture( [ buffer ] ).then( function ( _texture ) {					texture.copy( _texture );					texture.needsUpdate = true;					if ( onLoad ) onLoad( texture );				} ).catch( onError );			}, onProgress, onError );			return texture;		}		/** Low-level transcoding API, exposed for use by KTX2Loader. */		parseInternalAsync( options ) {			const {				levels			} = options;			const buffers = new Set();			for ( let i = 0; i < levels.length; i ++ ) {				buffers.add( levels[ i ].data.buffer );			}			return this._createTexture( Array.from( buffers ), { ...options,				lowLevel: true			} );		}		/**   * @param {ArrayBuffer[]} buffers   * @param {object?} config   * @return {Promise<CompressedTexture>}   */		_createTexture( buffers, config = {} ) {			let worker;			let taskID;			const taskConfig = config;			let taskCost = 0;			for ( let i = 0; i < buffers.length; i ++ ) {				taskCost += buffers[ i ].byteLength;			}			const texturePending = this._allocateWorker( taskCost ).then( _worker => {				worker = _worker;				taskID = this.workerNextTaskID ++;				return new Promise( ( resolve, reject ) => {					worker._callbacks[ taskID ] = {						resolve,						reject					};					worker.postMessage( {						type: 'transcode',						id: taskID,						buffers: buffers,						taskConfig: taskConfig					}, buffers );				} );			} ).then( message => {				const {					mipmaps,					width,					height,					format				} = message;				const texture = new THREE.CompressedTexture( mipmaps, width, height, format, THREE.UnsignedByteType );				texture.minFilter = mipmaps.length === 1 ? THREE.LinearFilter : THREE.LinearMipmapLinearFilter;				texture.magFilter = THREE.LinearFilter;				texture.generateMipmaps = false;				texture.needsUpdate = true;				return texture;			} ); // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416)			texturePending.catch( () => true ).then( () => {				if ( worker && taskID ) {					worker._taskLoad -= taskCost;					delete worker._callbacks[ taskID ];				}			} ); // Cache the task result.			_taskCache.set( buffers[ 0 ], {				promise: texturePending			} );			return texturePending;		}		_initTranscoder() {			if ( ! this.transcoderPending ) {				// Load transcoder wrapper.				const jsLoader = new THREE.FileLoader( this.manager );				jsLoader.setPath( this.transcoderPath );				jsLoader.setWithCredentials( this.withCredentials );				const jsContent = new Promise( ( resolve, reject ) => {					jsLoader.load( 'basis_transcoder.js', resolve, undefined, reject );				} ); // Load transcoder WASM binary.				const binaryLoader = new THREE.FileLoader( this.manager );				binaryLoader.setPath( this.transcoderPath );				binaryLoader.setResponseType( 'arraybuffer' );				binaryLoader.setWithCredentials( this.withCredentials );				const binaryContent = new Promise( ( resolve, reject ) => {					binaryLoader.load( 'basis_transcoder.wasm', resolve, undefined, reject );				} );				this.transcoderPending = Promise.all( [ jsContent, binaryContent ] ).then( ( [ jsContent, binaryContent ] ) => {					const fn = BasisTextureLoader.BasisWorker.toString();					const body = [ '/* constants */', 'let _EngineFormat = ' + JSON.stringify( BasisTextureLoader.EngineFormat ), 'let _TranscoderFormat = ' + JSON.stringify( BasisTextureLoader.TranscoderFormat ), 'let _BasisFormat = ' + JSON.stringify( BasisTextureLoader.BasisFormat ), '/* basis_transcoder.js */', jsContent, '/* worker */', fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) ) ].join( '\n' );					this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );					this.transcoderBinary = binaryContent;				} );			}			return this.transcoderPending;		}		_allocateWorker( taskCost ) {			return this._initTranscoder().then( () => {				if ( this.workerPool.length < this.workerLimit ) {					const worker = new Worker( this.workerSourceURL );					worker._callbacks = {};					worker._taskLoad = 0;					worker.postMessage( {						type: 'init',						config: this.workerConfig,						transcoderBinary: this.transcoderBinary					} );					worker.onmessage = function ( e ) {						const message = e.data;						switch ( message.type ) {							case 'transcode':								worker._callbacks[ message.id ].resolve( message );								break;							case 'error':								worker._callbacks[ message.id ].reject( message );								break;							default:								console.error( 'THREE.BasisTextureLoader: Unexpected message, "' + message.type + '"' );						}					};					this.workerPool.push( worker );				} else {					this.workerPool.sort( function ( a, b ) {						return a._taskLoad > b._taskLoad ? - 1 : 1;					} );				}				const worker = this.workerPool[ this.workerPool.length - 1 ];				worker._taskLoad += taskCost;				return worker;			} );		}		dispose() {			for ( let i = 0; i < this.workerPool.length; i ++ ) {				this.workerPool[ i ].terminate();			}			this.workerPool.length = 0;			return this;		}	}	/* CONSTANTS */	BasisTextureLoader.BasisFormat = {		ETC1S: 0,		UASTC_4x4: 1	};	BasisTextureLoader.TranscoderFormat = {		ETC1: 0,		ETC2: 1,		BC1: 2,		BC3: 3,		BC4: 4,		BC5: 5,		BC7_M6_OPAQUE_ONLY: 6,		BC7_M5: 7,		PVRTC1_4_RGB: 8,		PVRTC1_4_RGBA: 9,		ASTC_4x4: 10,		ATC_RGB: 11,		ATC_RGBA_INTERPOLATED_ALPHA: 12,		RGBA32: 13,		RGB565: 14,		BGR565: 15,		RGBA4444: 16	};	BasisTextureLoader.EngineFormat = {		RGBAFormat: THREE.RGBAFormat,		RGBA_ASTC_4x4_Format: THREE.RGBA_ASTC_4x4_Format,		RGBA_BPTC_Format: THREE.RGBA_BPTC_Format,		RGBA_ETC2_EAC_Format: THREE.RGBA_ETC2_EAC_Format,		RGBA_PVRTC_4BPPV1_Format: THREE.RGBA_PVRTC_4BPPV1_Format,		RGBA_S3TC_DXT5_Format: THREE.RGBA_S3TC_DXT5_Format,		RGB_ETC1_Format: THREE.RGB_ETC1_Format,		RGB_ETC2_Format: THREE.RGB_ETC2_Format,		RGB_PVRTC_4BPPV1_Format: THREE.RGB_PVRTC_4BPPV1_Format,		RGB_S3TC_DXT1_Format: THREE.RGB_S3TC_DXT1_Format	};	/* WEB WORKER */	BasisTextureLoader.BasisWorker = function () {		let config;		let transcoderPending;		let BasisModule;		const EngineFormat = _EngineFormat; // eslint-disable-line no-undef		const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef		const BasisFormat = _BasisFormat; // eslint-disable-line no-undef		onmessage = function ( e ) {			const message = e.data;			switch ( message.type ) {				case 'init':					config = message.config;					init( message.transcoderBinary );					break;				case 'transcode':					transcoderPending.then( () => {						try {							const {								width,								height,								hasAlpha,								mipmaps,								format							} = message.taskConfig.lowLevel ? transcodeLowLevel( message.taskConfig ) : transcode( message.buffers[ 0 ] );							const buffers = [];							for ( let i = 0; i < mipmaps.length; ++ i ) {								buffers.push( mipmaps[ i ].data.buffer );							}							self.postMessage( {								type: 'transcode',								id: message.id,								width,								height,								hasAlpha,								mipmaps,								format							}, buffers );						} catch ( error ) {							console.error( error );							self.postMessage( {								type: 'error',								id: message.id,								error: error.message							} );						}					} );					break;			}		};		function init( wasmBinary ) {			transcoderPending = new Promise( resolve => {				BasisModule = {					wasmBinary,					onRuntimeInitialized: resolve				};				BASIS( BasisModule ); // eslint-disable-line no-undef			} ).then( () => {				BasisModule.initializeBasis();			} );		}		function transcodeLowLevel( taskConfig ) {			const {				basisFormat,				width,				height,				hasAlpha			} = taskConfig;			const {				transcoderFormat,				engineFormat			} = getTranscoderFormat( basisFormat, width, height, hasAlpha );			const blockByteLength = BasisModule.getBytesPerBlockOrPixel( transcoderFormat );			assert( BasisModule.isFormatSupported( transcoderFormat ), 'THREE.BasisTextureLoader: Unsupported format.' );			const mipmaps = [];			if ( basisFormat === BasisFormat.ETC1S ) {				const transcoder = new BasisModule.LowLevelETC1SImageTranscoder();				const {					endpointCount,					endpointsData,					selectorCount,					selectorsData,					tablesData				} = taskConfig.globalData;				try {					let ok;					ok = transcoder.decodePalettes( endpointCount, endpointsData, selectorCount, selectorsData );					assert( ok, 'THREE.BasisTextureLoader: decodePalettes() failed.' );					ok = transcoder.decodeTables( tablesData );					assert( ok, 'THREE.BasisTextureLoader: decodeTables() failed.' );					for ( let i = 0; i < taskConfig.levels.length; i ++ ) {						const level = taskConfig.levels[ i ];						const imageDesc = taskConfig.globalData.imageDescs[ i ];						const dstByteLength = getTranscodedImageByteLength( transcoderFormat, level.width, level.height );						const dst = new Uint8Array( dstByteLength );						ok = transcoder.transcodeImage( transcoderFormat, dst, dstByteLength / blockByteLength, level.data, getWidthInBlocks( transcoderFormat, level.width ), getHeightInBlocks( transcoderFormat, level.height ), level.width, level.height, level.index, imageDesc.rgbSliceByteOffset, imageDesc.rgbSliceByteLength, imageDesc.alphaSliceByteOffset, imageDesc.alphaSliceByteLength, imageDesc.imageFlags, hasAlpha, false, 0, 0 );						assert( ok, 'THREE.BasisTextureLoader: transcodeImage() failed for level ' + level.index + '.' );						mipmaps.push( {							data: dst,							width: level.width,							height: level.height						} );					}				} finally {					transcoder.delete();				}			} else {				for ( let i = 0; i < taskConfig.levels.length; i ++ ) {					const level = taskConfig.levels[ i ];					const dstByteLength = getTranscodedImageByteLength( transcoderFormat, level.width, level.height );					const dst = new Uint8Array( dstByteLength );					const ok = BasisModule.transcodeUASTCImage( transcoderFormat, dst, dstByteLength / blockByteLength, level.data, getWidthInBlocks( transcoderFormat, level.width ), getHeightInBlocks( transcoderFormat, level.height ), level.width, level.height, level.index, 0, level.data.byteLength, 0, hasAlpha, false, 0, 0, - 1, - 1 );					assert( ok, 'THREE.BasisTextureLoader: transcodeUASTCImage() failed for level ' + level.index + '.' );					mipmaps.push( {						data: dst,						width: level.width,						height: level.height					} );				}			}			return {				width,				height,				hasAlpha,				mipmaps,				format: engineFormat			};		}		function transcode( buffer ) {			const basisFile = new BasisModule.BasisFile( new Uint8Array( buffer ) );			const basisFormat = basisFile.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;			const width = basisFile.getImageWidth( 0, 0 );			const height = basisFile.getImageHeight( 0, 0 );			const levels = basisFile.getNumLevels( 0 );			const hasAlpha = basisFile.getHasAlpha();			function cleanup() {				basisFile.close();				basisFile.delete();			}			const {				transcoderFormat,				engineFormat			} = getTranscoderFormat( basisFormat, width, height, hasAlpha );			if ( ! width || ! height || ! levels ) {				cleanup();				throw new Error( 'THREE.BasisTextureLoader:	Invalid texture' );			}			if ( ! basisFile.startTranscoding() ) {				cleanup();				throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' );			}			const mipmaps = [];			for ( let mip = 0; mip < levels; mip ++ ) {				const mipWidth = basisFile.getImageWidth( 0, mip );				const mipHeight = basisFile.getImageHeight( 0, mip );				const dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, mip, transcoderFormat ) );				const status = basisFile.transcodeImage( dst, 0, mip, transcoderFormat, 0, hasAlpha );				if ( ! status ) {					cleanup();					throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' );				}				mipmaps.push( {					data: dst,					width: mipWidth,					height: mipHeight				} );			}			cleanup();			return {				width,				height,				hasAlpha,				mipmaps,				format: engineFormat			};		} //		// Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),		// device capabilities, and texture dimensions. The list below ranks the formats separately		// for ETC1S and UASTC.		//		// In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at		// significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently		// chooses RGBA32 only as a last resort and does not expose that option to the caller.		const FORMAT_OPTIONS = [ {			if: 'astcSupported',			basisFormat: [ BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4 ],			engineFormat: [ EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format ],			priorityETC1S: Infinity,			priorityUASTC: 1,			needsPowerOfTwo: false		}, {			if: 'bptcSupported',			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5 ],			engineFormat: [ EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format ],			priorityETC1S: 3,			priorityUASTC: 2,			needsPowerOfTwo: false		}, {			if: 'dxtSupported',			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ],			engineFormat: [ EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],			priorityETC1S: 4,			priorityUASTC: 5,			needsPowerOfTwo: false		}, {			if: 'etc2Supported',			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC2 ],			engineFormat: [ EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format ],			priorityETC1S: 1,			priorityUASTC: 3,			needsPowerOfTwo: false		}, {			if: 'etc1Supported',			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC1 ],			engineFormat: [ EngineFormat.RGB_ETC1_Format, EngineFormat.RGB_ETC1_Format ],			priorityETC1S: 2,			priorityUASTC: 4,			needsPowerOfTwo: false		}, {			if: 'pvrtcSupported',			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],			transcoderFormat: [ TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA ],			engineFormat: [ EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format ],			priorityETC1S: 5,			priorityUASTC: 6,			needsPowerOfTwo: true		} ];		const ETC1S_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {			return a.priorityETC1S - b.priorityETC1S;		} );		const UASTC_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {			return a.priorityUASTC - b.priorityUASTC;		} );		function getTranscoderFormat( basisFormat, width, height, hasAlpha ) {			let transcoderFormat;			let engineFormat;			const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;			for ( let i = 0; i < options.length; i ++ ) {				const opt = options[ i ];				if ( ! config[ opt.if ] ) continue;				if ( ! opt.basisFormat.includes( basisFormat ) ) continue;				if ( opt.needsPowerOfTwo && ! ( isPowerOfTwo( width ) && isPowerOfTwo( height ) ) ) continue;				transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ];				engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ];				return {					transcoderFormat,					engineFormat				};			}			console.warn( 'THREE.BasisTextureLoader: No suitable compressed texture format found. Decoding to RGBA32.' );			transcoderFormat = TranscoderFormat.RGBA32;			engineFormat = EngineFormat.RGBAFormat;			return {				transcoderFormat,				engineFormat			};		}		function assert( ok, message ) {			if ( ! ok ) throw new Error( message );		}		function getWidthInBlocks( transcoderFormat, width ) {			return Math.ceil( width / BasisModule.getFormatBlockWidth( transcoderFormat ) );		}		function getHeightInBlocks( transcoderFormat, height ) {			return Math.ceil( height / BasisModule.getFormatBlockHeight( transcoderFormat ) );		}		function getTranscodedImageByteLength( transcoderFormat, width, height ) {			const blockByteLength = BasisModule.getBytesPerBlockOrPixel( transcoderFormat );			if ( BasisModule.formatIsUncompressed( transcoderFormat ) ) {				return width * height * blockByteLength;			}			if ( transcoderFormat === TranscoderFormat.PVRTC1_4_RGB || transcoderFormat === TranscoderFormat.PVRTC1_4_RGBA ) {				// GL requires extra padding for very small textures:				// https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt				const paddedWidth = width + 3 & ~ 3;				const paddedHeight = height + 3 & ~ 3;				return ( Math.max( 8, paddedWidth ) * Math.max( 8, paddedHeight ) * 4 + 7 ) / 8;			}			return getWidthInBlocks( transcoderFormat, width ) * getHeightInBlocks( transcoderFormat, height ) * blockByteLength;		}		function isPowerOfTwo( value ) {			if ( value <= 2 ) return true;			return ( value & value - 1 ) === 0 && value !== 0;		}	};	THREE.BasisTextureLoader = BasisTextureLoader;} )();
 |