Dies ist das Repository meines kleinen Portfolios.
Im Hintergrund läuft eine Planetensimulation, geschrieben in JavaScript und Three.js.
Die zu sehenden Texturen stammen von:
https://www.solarsystemscope.com/textures/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
4.6 KiB
251 lines
4.6 KiB
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 };
|
|
|