123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- 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 };
|