| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 | ( function () {	/* *	 PVR v2 (legacy) parser *   TODO : Add Support for PVR v3 format *   TODO : implement loadMipmaps option */	class PVRLoader extends THREE.CompressedTextureLoader {		constructor( manager ) {			super( manager );		}		parse( buffer, loadMipmaps ) {			const headerLengthInt = 13;			const header = new Uint32Array( buffer, 0, headerLengthInt );			const pvrDatas = {				buffer: buffer,				header: header,				loadMipmaps: loadMipmaps			};			if ( header[ 0 ] === 0x03525650 ) {				// PVR v3				return _parseV3( pvrDatas );			} else if ( header[ 11 ] === 0x21525650 ) {				// PVR v2				return _parseV2( pvrDatas );			} else {				console.error( 'THREE.PVRLoader: Unknown PVR format.' );			}		}	}	function _parseV3( pvrDatas ) {		const header = pvrDatas.header;		let bpp, format;		const metaLen = header[ 12 ],			pixelFormat = header[ 2 ],			height = header[ 6 ],			width = header[ 7 ],			// numSurfs = header[ 9 ],			numFaces = header[ 10 ],			numMipmaps = header[ 11 ];		switch ( pixelFormat ) {			case 0:				// PVRTC 2bpp RGB				bpp = 2;				format = THREE.RGB_PVRTC_2BPPV1_Format;				break;			case 1:				// PVRTC 2bpp RGBA				bpp = 2;				format = THREE.RGBA_PVRTC_2BPPV1_Format;				break;			case 2:				// PVRTC 4bpp RGB				bpp = 4;				format = THREE.RGB_PVRTC_4BPPV1_Format;				break;			case 3:				// PVRTC 4bpp RGBA				bpp = 4;				format = THREE.RGBA_PVRTC_4BPPV1_Format;				break;			default:				console.error( 'THREE.PVRLoader: Unsupported PVR format:', pixelFormat );		}		pvrDatas.dataPtr = 52 + metaLen;		pvrDatas.bpp = bpp;		pvrDatas.format = format;		pvrDatas.width = width;		pvrDatas.height = height;		pvrDatas.numSurfaces = numFaces;		pvrDatas.numMipmaps = numMipmaps;		pvrDatas.isCubemap = numFaces === 6;		return _extract( pvrDatas );	}	function _parseV2( pvrDatas ) {		const header = pvrDatas.header;		const headerLength = header[ 0 ],			height = header[ 1 ],			width = header[ 2 ],			numMipmaps = header[ 3 ],			flags = header[ 4 ],			// dataLength = header[ 5 ],			// bpp =  header[ 6 ],			// bitmaskRed = header[ 7 ],			// bitmaskGreen = header[ 8 ],			// bitmaskBlue = header[ 9 ],			bitmaskAlpha = header[ 10 ],			// pvrTag = header[ 11 ],			numSurfs = header[ 12 ];		const TYPE_MASK = 0xff;		const PVRTC_2 = 24,			PVRTC_4 = 25;		const formatFlags = flags & TYPE_MASK;		let bpp, format;		const _hasAlpha = bitmaskAlpha > 0;		if ( formatFlags === PVRTC_4 ) {			format = _hasAlpha ? THREE.RGBA_PVRTC_4BPPV1_Format : THREE.RGB_PVRTC_4BPPV1_Format;			bpp = 4;		} else if ( formatFlags === PVRTC_2 ) {			format = _hasAlpha ? THREE.RGBA_PVRTC_2BPPV1_Format : THREE.RGB_PVRTC_2BPPV1_Format;			bpp = 2;		} else {			console.error( 'THREE.PVRLoader: Unknown PVR format:', formatFlags );		}		pvrDatas.dataPtr = headerLength;		pvrDatas.bpp = bpp;		pvrDatas.format = format;		pvrDatas.width = width;		pvrDatas.height = height;		pvrDatas.numSurfaces = numSurfs;		pvrDatas.numMipmaps = numMipmaps + 1; // guess cubemap type seems tricky in v2		// it juste a pvr containing 6 surface (no explicit cubemap type)		pvrDatas.isCubemap = numSurfs === 6;		return _extract( pvrDatas );	}	function _extract( pvrDatas ) {		const pvr = {			mipmaps: [],			width: pvrDatas.width,			height: pvrDatas.height,			format: pvrDatas.format,			mipmapCount: pvrDatas.numMipmaps,			isCubemap: pvrDatas.isCubemap		};		const buffer = pvrDatas.buffer;		let dataOffset = pvrDatas.dataPtr,			dataSize = 0,			blockSize = 0,			blockWidth = 0,			blockHeight = 0,			widthBlocks = 0,			heightBlocks = 0;		const bpp = pvrDatas.bpp,			numSurfs = pvrDatas.numSurfaces;		if ( bpp === 2 ) {			blockWidth = 8;			blockHeight = 4;		} else {			blockWidth = 4;			blockHeight = 4;		}		blockSize = blockWidth * blockHeight * bpp / 8;		pvr.mipmaps.length = pvrDatas.numMipmaps * numSurfs;		let mipLevel = 0;		while ( mipLevel < pvrDatas.numMipmaps ) {			const sWidth = pvrDatas.width >> mipLevel,				sHeight = pvrDatas.height >> mipLevel;			widthBlocks = sWidth / blockWidth;			heightBlocks = sHeight / blockHeight; // Clamp to minimum number of blocks			if ( widthBlocks < 2 ) widthBlocks = 2;			if ( heightBlocks < 2 ) heightBlocks = 2;			dataSize = widthBlocks * heightBlocks * blockSize;			for ( let surfIndex = 0; surfIndex < numSurfs; surfIndex ++ ) {				const byteArray = new Uint8Array( buffer, dataOffset, dataSize );				const mipmap = {					data: byteArray,					width: sWidth,					height: sHeight				};				pvr.mipmaps[ surfIndex * pvrDatas.numMipmaps + mipLevel ] = mipmap;				dataOffset += dataSize;			}			mipLevel ++;		}		return pvr;	}	THREE.PVRLoader = PVRLoader;} )();
 |