252 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			252 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									CompressedTextureLoader,
							 | 
						||
| 
								 | 
							
									RGBA_PVRTC_2BPPV1_Format,
							 | 
						||
| 
								 | 
							
									RGBA_PVRTC_4BPPV1_Format,
							 | 
						||
| 
								 | 
							
									RGB_PVRTC_2BPPV1_Format,
							 | 
						||
| 
								 | 
							
									RGB_PVRTC_4BPPV1_Format
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 *	 PVR v2 (legacy) parser
							 | 
						||
| 
								 | 
							
								 *   TODO : Add Support for PVR v3 format
							 | 
						||
| 
								 | 
							
								 *   TODO : implement loadMipmaps option
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class PVRLoader extends 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 = RGB_PVRTC_2BPPV1_Format;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case 1 : // PVRTC 2bpp RGBA
							 | 
						||
| 
								 | 
							
											bpp = 2;
							 | 
						||
| 
								 | 
							
											format = RGBA_PVRTC_2BPPV1_Format;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case 2 : // PVRTC 4bpp RGB
							 | 
						||
| 
								 | 
							
											bpp = 4;
							 | 
						||
| 
								 | 
							
											format = RGB_PVRTC_4BPPV1_Format;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										case 3 : // PVRTC 4bpp RGBA
							 | 
						||
| 
								 | 
							
											bpp = 4;
							 | 
						||
| 
								 | 
							
											format = 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 ? RGBA_PVRTC_4BPPV1_Format : RGB_PVRTC_4BPPV1_Format;
							 | 
						||
| 
								 | 
							
										bpp = 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( formatFlags === PVRTC_2 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										format = _hasAlpha ? RGBA_PVRTC_2BPPV1_Format : 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;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { PVRLoader };
							 |