//----------------------------------------------------------------------------// Texture* PVRImageCodec::load(const RawDataContainer& data, Texture* result) { const PVR_Texture_Header* pvr_header = reinterpret_cast<const PVR_Texture_Header*>(data.getDataPtr()); // convert header to big endian if required PVR_Texture_Header converted_pvr_header; if (!PVRTIsLittleEndian()) { converted_pvr_header = *pvr_header; PVRTuint32* data = reinterpret_cast<PVRTuint32*>(&converted_pvr_header); for (uint i = 0; i < sizeof(PVR_Texture_Header) / sizeof(PVRTuint32); i++) PVRTByteSwap(reinterpret_cast<PVRTuint8*>(data++), sizeof(PVRTuint32)); pvr_header = &converted_pvr_header; } // perform checks for old PVR psPVRHeader if (pvr_header->dwHeaderSize != sizeof(PVR_Texture_Header)) { // Unknow or old format Logger::getSingletonPtr()->logEvent( "PVRImageCodec::load - unknown or old texture format. " "Use PVRTexTool to save in appropriate format.", Errors); return 0; } if (pvr_header->dwpfFlags & PVRTEX_CUBEMAP) { //Cube maps are not supported Logger::getSingletonPtr()->logEvent( "PVRImageCodec::load - cubemap textures unsupported.", Errors); return 0; } /* Only accept untwiddled data UNLESS texture format is PVRTC */ if (((pvr_header->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) && ((pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC2) && ((pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC4)) { // We need to load untwiddled textures -- hw will twiddle for us. Logger::getSingletonPtr()->logEvent( "PVRImageCodec::load - Texture should be untwiddled", Errors); return 0; } CEGUI::Texture::PixelFormat cefmt; bool is_compressed_format = false; switch (pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) { case OGL_RGBA_4444: cefmt = CEGUI::Texture::PF_RGBA_4444; break; case OGL_RGBA_5551: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "pixel format RGBA_5551 not supported.", Errors); return 0; case OGL_RGB_565: cefmt = CEGUI::Texture::PF_RGB_565; break; case OGL_RGB_555: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "pixel format RGB_555 not supported.", Errors); return 0; case OGL_I_8: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "pixel format I_8 not supported.", Errors); return 0; case OGL_AI_88: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "pixel format AI_88 not supported.", Errors); return 0; case OGL_BGRA_8888: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "pixel format BGRA8888 not supported.", Errors); return 0; case OGL_RGBA_8888: cefmt = CEGUI::Texture::PF_RGBA; break; case OGL_RGB_888: cefmt = CEGUI::Texture::PF_RGB; break; case MGLPT_PVRTC2: case OGL_PVRTC2: cefmt = CEGUI::Texture::PF_PVRTC2; is_compressed_format = true; break; case MGLPT_PVRTC4: case OGL_PVRTC4: cefmt = CEGUI::Texture::PF_PVRTC4; is_compressed_format = true; break; default: Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - " "wrong pvr pixel format.", Errors); return 0; } const void* texture_data = reinterpret_cast<const void*>(data.getDataPtr() + pvr_header->dwHeaderSize); const uint size_x = pvr_header->dwWidth; const uint size_y = pvr_header->dwHeight; if (is_compressed_format) { if (result->isPixelFormatSupported(cefmt)) { result->loadFromMemory(texture_data, Sizef(static_cast<float>(size_x), static_cast<float>(size_y)), cefmt); } else { // Convert PVRTC to 32-bit RGBA PVRTuint8* decompressed_texture = new PVRTuint8[size_x * size_y * 4]; int bit_mode = (pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) == OGL_PVRTC2; PVRTDecompressPVRTC(texture_data, bit_mode, size_x, size_y, decompressed_texture); cefmt = CEGUI::Texture::PF_RGBA; // Redefine to uncompressed format result->loadFromMemory(decompressed_texture, Sizef(static_cast<float>(size_x), static_cast<float>(size_y)), cefmt); delete[] decompressed_texture; } } else { // Perform raw data load from textureData result->loadFromMemory(texture_data, Sizef(static_cast<float>(size_x), static_cast<float>(size_y)), cefmt); } return result; }
/*!*************************************************************************** @Function PVRTTextureLoadFromPointer @Input pointer Pointer to header-texture's structure @Modified texName the OpenGL ES texture name as returned by glBindTexture @Modified psTextureHeader Pointer to a PVRTextureHeaderV3 struct. Modified to contain the header data of the returned texture Ignored if NULL. @Input bAllowDecompress Allow decompression if PVRTC is not supported in hardware. @Input nLoadFromLevel Which mip map level to start loading from (0=all) @Input texPtr If null, texture follows header, else texture is here. @Modified pMetaData If a valid map is supplied, this will return any and all MetaDataBlocks stored in the texture, organised by DevFourCC then identifier. Supplying NULL will ignore all MetaData. @Return PVR_SUCCESS on success @Description Allows textures to be stored in C header files and loaded in. Can load parts of a mip mapped texture (i.e. skipping the highest detailed levels). In OpenGL Cube Map, each texture's up direction is defined as next (view direction, up direction), (+x,-y)(-x,-y)(+y,+z)(-y,-z)(+z,-y)(-z,-y). Sets the texture MIN/MAG filter to GL_LINEAR_MIPMAP_NEAREST/GL_LINEAR if mip maps are present, GL_LINEAR/GL_LINEAR otherwise. *****************************************************************************/ EPVRTError PVRTTextureLoadFromPointer( const void* pointer, GLuint *const texName, const void *psTextureHeader, bool bAllowDecompress, const unsigned int nLoadFromLevel, const void * const texPtr, CPVRTMap<unsigned int, CPVRTMap<unsigned int, MetaDataBlock> > *pMetaData) { //Compression bools bool bIsCompressedFormatSupported=false; bool bIsCompressedFormat=false; bool bIsLegacyPVR=false; bool bUsesTexImage3D=false; //Texture setup PVRTextureHeaderV3 sTextureHeader; PVRTuint8* pTextureData=NULL; //Just in case header and pointer for decompression. PVRTextureHeaderV3 sTextureHeaderDecomp; void* pDecompressedData=NULL; //Check if it's an old header format if((*(PVRTuint32*)pointer)!=PVRTEX3_IDENT) { //Convert the texture header to the new format. PVRTConvertOldTextureHeaderToV3((PVR_Texture_Header*)pointer,sTextureHeader,pMetaData); //Get the texture data. pTextureData = texPtr? (PVRTuint8*)texPtr:(PVRTuint8*)pointer+*(PVRTuint32*)pointer; bIsLegacyPVR=true; } else { //Get the header from the main pointer. sTextureHeader=*(PVRTextureHeaderV3*)pointer; //Get the texture data. pTextureData = texPtr? (PVRTuint8*)texPtr:(PVRTuint8*)pointer+PVRTEX3_HEADERSIZE+sTextureHeader.u32MetaDataSize; if (pMetaData) { //Read in all the meta data. PVRTuint32 metaDataSize=0; while (metaDataSize<sTextureHeader.u32MetaDataSize) { //Read the DevFourCC and advance the pointer offset. PVRTuint32 DevFourCC=*(PVRTuint32*)((PVRTuint8*)pointer+PVRTEX3_HEADERSIZE+metaDataSize); metaDataSize+=sizeof(DevFourCC); //Read the Key and advance the pointer offset. PVRTuint32 u32Key=*(PVRTuint32*)((PVRTuint8*)pointer+PVRTEX3_HEADERSIZE+metaDataSize); metaDataSize+=sizeof(u32Key); //Read the DataSize and advance the pointer offset. PVRTuint32 u32DataSize = *(PVRTuint32*)((PVRTuint8*)pointer+PVRTEX3_HEADERSIZE+metaDataSize); metaDataSize+=sizeof(u32DataSize); //Get the current meta data. MetaDataBlock& currentMetaData = (*pMetaData)[DevFourCC][u32Key]; //Assign the values to the meta data. currentMetaData.DevFOURCC=DevFourCC; currentMetaData.u32Key=u32Key; currentMetaData.u32DataSize=u32DataSize; //Check for data, if there is any, read it into the meta data. if(u32DataSize > 0) { //Allocate memory. currentMetaData.Data = new PVRTuint8[u32DataSize]; //Copy the data. memcpy(currentMetaData.Data, ((PVRTuint8*)pointer+PVRTEX3_HEADERSIZE+metaDataSize), u32DataSize); //Advance the meta data size. metaDataSize+=u32DataSize; } } } } //Return the PVRTextureHeader. if (psTextureHeader) { *(PVRTextureHeaderV3*)psTextureHeader=sTextureHeader; } //Setup GL Texture format values. GLenum eTextureFormat = 0; GLenum eTextureInternalFormat = 0; // often this is the same as textureFormat, but not for BGRA8888 on iOS, for instance GLenum eTextureType = 0; //Get the OGLES format values. PVRTGetOGLES3TextureFormat(sTextureHeader,eTextureInternalFormat,eTextureFormat,eTextureType); bool bIsPVRTCSupported = CPVRTgles3Ext::IsGLExtensionSupported("GL_IMG_texture_compression_pvrtc"); #ifndef TARGET_OS_IPHONE bool bIsBGRA8888Supported = CPVRTgles3Ext::IsGLExtensionSupported("GL_IMG_texture_format_BGRA8888"); #else bool bIsBGRA8888Supported = CPVRTgles3Ext::IsGLExtensionSupported("GL_APPLE_texture_format_BGRA8888"); #endif #ifndef TARGET_OS_IPHONE bool bIsETCSupported = CPVRTgles3Ext::IsGLExtensionSupported("GL_OES_compressed_ETC1_RGB8_texture"); #endif //Check for compressed formats if (eTextureFormat==0 && eTextureType==0 && eTextureInternalFormat!=0) { if (eTextureInternalFormat>=GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG && eTextureInternalFormat<=GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) { //Check for PVRTCI support. if(bIsPVRTCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; } else { //Try to decompress the texture. if(bAllowDecompress) { //Output a warning. PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: PVRTC not supported. Converting to RGBA8888 instead.\n"); //Modify boolean values. bIsCompressedFormatSupported = false; bIsCompressedFormat = true; //Check if it's 2bpp. bool bIs2bppPVRTC = (eTextureInternalFormat==GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG || eTextureInternalFormat==GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG); //Change texture format. eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; //Create a near-identical texture header for the decompressed header. sTextureHeaderDecomp = sTextureHeader; sTextureHeaderDecomp.u32ChannelType=ePVRTVarTypeUnsignedByteNorm; sTextureHeaderDecomp.u32ColourSpace=ePVRTCSpacelRGB; sTextureHeaderDecomp.u64PixelFormat=PVRTGENPIXELID4('r','g','b','a',8,8,8,8); //Allocate enough memory for the decompressed data. OGLES2, so only decompress one surface/face. pDecompressedData = malloc(PVRTGetTextureDataSize(sTextureHeaderDecomp, PVRTEX_ALLMIPLEVELS, false, true) ); //Check the malloc. if (!pDecompressedData) { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: Unable to allocate memory to decompress texture.\n"); return PVR_FAIL; } //Get the dimensions for the current MIP level. PVRTuint32 uiMIPWidth = sTextureHeaderDecomp.u32Width>>nLoadFromLevel; PVRTuint32 uiMIPHeight = sTextureHeaderDecomp.u32Height>>nLoadFromLevel; //Setup temporary variables. PVRTuint8* pTempDecompData = (PVRTuint8*)pDecompressedData; PVRTuint8* pTempCompData = (PVRTuint8*)pTextureData; if (bIsLegacyPVR) { //Decompress all the MIP levels. for (PVRTuint32 uiFace=0;uiFace<sTextureHeader.u32NumFaces;++uiFace) { for (PVRTuint32 uiMIPMap=nLoadFromLevel;uiMIPMap<sTextureHeader.u32MIPMapCount;++uiMIPMap) { //Get the face offset. Varies per MIP level. PVRTuint32 decompressedFaceOffset = PVRTGetTextureDataSize(sTextureHeaderDecomp, uiMIPMap, false, false); PVRTuint32 compressedFaceOffset = PVRTGetTextureDataSize(sTextureHeader, uiMIPMap, false, false); //Decompress the texture data. PVRTDecompressPVRTC(pTempCompData,bIs2bppPVRTC?1:0,uiMIPWidth,uiMIPHeight,pTempDecompData); //Move forward through the pointers. pTempDecompData+=decompressedFaceOffset; pTempCompData+=compressedFaceOffset; //Work out the current MIP dimensions. uiMIPWidth=PVRT_MAX(1,uiMIPWidth>>1); uiMIPHeight=PVRT_MAX(1,uiMIPHeight>>1); } //Reset the dims. uiMIPWidth=sTextureHeader.u32Width; uiMIPHeight=sTextureHeader.u32Height; } } else { //Decompress all the MIP levels. for (PVRTuint32 uiMIPMap=nLoadFromLevel;uiMIPMap<sTextureHeader.u32MIPMapCount;++uiMIPMap) { //Get the face offset. Varies per MIP level. PVRTuint32 decompressedFaceOffset = PVRTGetTextureDataSize(sTextureHeaderDecomp, uiMIPMap, false, false); PVRTuint32 compressedFaceOffset = PVRTGetTextureDataSize(sTextureHeader, uiMIPMap, false, false); for (PVRTuint32 uiFace=0;uiFace<sTextureHeader.u32NumFaces;++uiFace) { //Decompress the texture data. PVRTDecompressPVRTC(pTempCompData,bIs2bppPVRTC?1:0,uiMIPWidth,uiMIPHeight,pTempDecompData); //Move forward through the pointers. pTempDecompData+=decompressedFaceOffset; pTempCompData+=compressedFaceOffset; } //Work out the current MIP dimensions. uiMIPWidth=PVRT_MAX(1,uiMIPWidth>>1); uiMIPHeight=PVRT_MAX(1,uiMIPHeight>>1); } } } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC not supported.\n"); return PVR_FAIL; } } }
/*!*************************************************************************** @Function PVRTTextureLoadFromPointer @Input pointer Pointer to header-texture's structure @Modified texName the OpenGL ES texture name as returned by glBindTexture @Modified psTextureHeader Pointer to a PVR_Texture_Header struct. Modified to contain the header data of the returned texture Ignored if NULL. @Input bAllowDecompress Allow decompression if PVRTC is not supported in hardware. @Input nLoadFromLevel Which mipmap level to start loading from (0=all) @Input texPtr If null, texture follows header, else texture is here. @Return PVR_SUCCESS on success @Description Allows textures to be stored in C header files and loaded in. Can load parts of a mipmaped texture (ie skipping the highest detailed levels).In OpenGL Cube Map, each texture's up direction is defined as next (view direction, up direction), (+x,-y)(-x,-y)(+y,+z)(-y,-z)(+z,-y)(-z,-y). Sets the texture MIN/MAG filter to GL_LINEAR_MIPMAP_NEAREST/GL_LINEAR if mipmaps are present, GL_LINEAR/GL_LINEAR otherwise. *****************************************************************************/ EPVRTError PVRTTextureLoadFromPointer( const void* pointer, GLuint *const texName, const void *psTextureHeader, bool bAllowDecompress, const unsigned int nLoadFromLevel, const void * const texPtr) { PVR_Texture_Header* psPVRHeader = (PVR_Texture_Header*)pointer; unsigned int u32NumSurfs; // perform checks for old PVR psPVRHeader if(psPVRHeader->dwHeaderSize!=sizeof(PVR_Texture_Header)) { // Header V1 if(psPVRHeader->dwHeaderSize==PVRTEX_V1_HEADER_SIZE) { // react to old psPVRHeader: i.e. fill in numsurfs as this is missing from old header PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: this is an old pvr" " - you can use PVRTexTool to update its header.\n"); if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { // not a pvr at all PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: not a valid pvr.\n"); return PVR_FAIL; } } else { // Header V2 if(psPVRHeader->dwNumSurfs<1) { // encoded with old version of PVRTexTool before zero numsurfs bug found. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) u32NumSurfs = 6; else u32NumSurfs = 1; } else { u32NumSurfs = psPVRHeader->dwNumSurfs; } } GLuint textureName; GLenum eTextureFormat = 0; GLenum eTextureInternalFormat = 0; // often this is the same as textureFormat, but not for BGRA8888 on the iPhone, for instance GLenum eTextureType = 0; GLenum eTarget; bool bIsPVRTCSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_compression_pvrtc"); #ifndef TARGET_OS_IPHONE bool bIsBGRA8888Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_format_BGRA8888"); #else bool bIsBGRA8888Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_APPLE_texture_format_BGRA8888"); #endif bool bIsFloat16Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_texture_half_float"); bool bIsFloat32Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_texture_float"); #ifndef TARGET_OS_IPHONE bool bIsETCSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_compressed_ETC1_RGB8_texture"); #endif *texName = 0; // install warning value bool bIsCompressedFormatSupported = false, bIsCompressedFormat = false; /* Only accept untwiddled data UNLESS texture format is PVRTC */ if ( ((psPVRHeader->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC2) && ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC4) ) { // We need to load untwiddled textures -- GL will twiddle for us. PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: texture should be untwiddled.\n"); return PVR_FAIL; } unsigned int ePixelType = psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE; switch(ePixelType) { case OGL_RGBA_4444: eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_SHORT_4_4_4_4; break; case OGL_RGBA_5551: eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_UNSIGNED_SHORT_5_5_5_1; break; case OGL_RGBA_8888: eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE ; break; /* New OGL Specific Formats Added */ case OGL_RGB_565: eTextureFormat = eTextureInternalFormat = GL_RGB ; eTextureType = GL_UNSIGNED_SHORT_5_6_5; break; case OGL_RGB_555: PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: pixel type OGL_RGB_555 not supported.\n"); return PVR_FAIL; // Deal with exceptional case case OGL_RGB_888: eTextureFormat = eTextureInternalFormat = GL_RGB ; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_I_8: eTextureFormat = eTextureInternalFormat = GL_LUMINANCE; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_AI_88: eTextureFormat = eTextureInternalFormat = GL_LUMINANCE_ALPHA ; eTextureType = GL_UNSIGNED_BYTE; break; case MGLPT_PVRTC2: case OGL_PVRTC2: if(bIsPVRTCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ; // PVRTC2 } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: PVRTC2 not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC2 not supported.\n"); return PVR_FAIL; } } break; case MGLPT_PVRTC4: case OGL_PVRTC4: if(bIsPVRTCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = psPVRHeader->dwAlphaBitMask==0 ? GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ; // PVRTC4 } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = eTextureInternalFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: PVRTC4 not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC4 not supported.\n"); return PVR_FAIL; } } break; case OGL_A_8: eTextureFormat = eTextureInternalFormat = GL_ALPHA; eTextureType = GL_UNSIGNED_BYTE; break; case OGL_BGRA_8888: if(bIsBGRA8888Supported) { eTextureType = GL_UNSIGNED_BYTE; #ifndef __APPLE__ eTextureFormat = eTextureInternalFormat = GL_BGRA; #else eTextureFormat = GL_BGRA; eTextureInternalFormat = GL_RGBA; #endif } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported.\n"); return PVR_FAIL; } break; case D3D_ABGR_16161616F: if(bIsFloat16Supported) { eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_HALF_FLOAT_OES; } break; case D3D_ABGR_32323232F: if(bIsFloat32Supported) { eTextureFormat = eTextureInternalFormat = GL_RGBA ; eTextureType = GL_FLOAT; } break; #ifndef TARGET_OS_IPHONE case ETC_RGB_4BPP: if(bIsETCSupported) { bIsCompressedFormatSupported = bIsCompressedFormat = true; eTextureFormat = GL_ETC1_RGB8_OES; } else { if(bAllowDecompress) { bIsCompressedFormatSupported = false; bIsCompressedFormat = true; eTextureFormat = GL_RGBA; eTextureType = GL_UNSIGNED_BYTE; PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: ETC not supported. Converting to RGBA8888 instead.\n"); } else { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: ETC not supported.\n"); return PVR_FAIL; } } break; #endif default: // NOT SUPPORTED PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: pixel type not supported.\n"); return PVR_FAIL; } // load the texture up glPixelStorei(GL_UNPACK_ALIGNMENT,1); // Never have row-aligned in psPVRHeaders glGenTextures(1, &textureName); // check that this data is cube map data or not. if(psPVRHeader->dwpfFlags & PVRTEX_CUBEMAP) eTarget = GL_TEXTURE_CUBE_MAP; else eTarget = GL_TEXTURE_2D; glBindTexture(eTarget, textureName); if(glGetError()) { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glBindTexture() failed.\n"); return PVR_FAIL; } for(unsigned int i=0; i<u32NumSurfs; i++) { char *theTexturePtr = (texPtr? (char*)texPtr : (char*)psPVRHeader + psPVRHeader->dwHeaderSize) + psPVRHeader->dwTextureDataSize * i; char *theTextureToLoad = 0; int nMIPMapLevel; int nTextureLevelsNeeded = (psPVRHeader->dwpfFlags & PVRTEX_MIPMAP)? psPVRHeader->dwMipMapCount : 0; unsigned int nSizeX= psPVRHeader->dwWidth, nSizeY = psPVRHeader->dwHeight; unsigned int CompressedImageSize = 0; for(nMIPMapLevel = 0; nMIPMapLevel <= nTextureLevelsNeeded; nSizeX=PVRT_MAX(nSizeX/2, (unsigned int)1), nSizeY=PVRT_MAX(nSizeY/2, (unsigned int)1), nMIPMapLevel++) { theTextureToLoad = theTexturePtr; // Load the Texture // If the texture is PVRTC or ETC then use GLCompressedTexImage2D if(bIsCompressedFormat) { /* Calculate how many bytes this MIP level occupies */ if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC2_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC2_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } else if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC4) { CompressedImageSize = ( PVRT_MAX(nSizeX, PVRTC4_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, PVRTC4_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } else {// ETC CompressedImageSize = ( PVRT_MAX(nSizeX, ETC_MIN_TEXWIDTH) * PVRT_MAX(nSizeY, ETC_MIN_TEXHEIGHT) * psPVRHeader->dwBitCount) / 8; } if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { if(bIsCompressedFormatSupported) { if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) { /* Load compressed texture data at selected MIP level */ glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, nMIPMapLevel-nLoadFromLevel, eTextureFormat, nSizeX, nSizeY, 0, CompressedImageSize, theTextureToLoad); } else { /* Load compressed texture data at selected MIP level */ glCompressedTexImage2D(GL_TEXTURE_2D, nMIPMapLevel-nLoadFromLevel, eTextureFormat, nSizeX, nSizeY, 0, CompressedImageSize, theTextureToLoad); } } else { // Convert PVRTC to 32-bit PVRTuint8 *u8TempTexture = (PVRTuint8*)malloc(nSizeX*nSizeY*4); if ((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { PVRTDecompressPVRTC(theTextureToLoad, 1, nSizeX, nSizeY, u8TempTexture); } else if((psPVRHeader->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC4) { PVRTDecompressPVRTC(theTextureToLoad, 0, nSizeX, nSizeY, u8TempTexture); } else { // ETC PVRTDecompressETC(theTextureToLoad, nSizeX, nSizeY, u8TempTexture, 0); } if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) {// Load compressed cubemap data at selected MIP level // Upload the texture as 32-bits glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,GL_RGBA, nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); FREE(u8TempTexture); } else {// Load compressed 2D data at selected MIP level // Upload the texture as 32-bits glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,GL_RGBA, nSizeX,nSizeY,0, GL_RGBA,GL_UNSIGNED_BYTE,u8TempTexture); FREE(u8TempTexture); } } } } else { if(((signed int)nMIPMapLevel - (signed int)nLoadFromLevel) >= 0) { if(psPVRHeader->dwpfFlags&PVRTEX_CUBEMAP) { /* Load uncompressed texture data at selected MIP level */ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,nMIPMapLevel-nLoadFromLevel,eTextureInternalFormat,nSizeX,nSizeY, 0, eTextureFormat,eTextureType,theTextureToLoad); } else { /* Load uncompressed texture data at selected MIP level */ glTexImage2D(GL_TEXTURE_2D,nMIPMapLevel-nLoadFromLevel,eTextureInternalFormat,nSizeX,nSizeY,0,eTextureFormat,eTextureType,theTextureToLoad); } } } if(glGetError()) { PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexImage2D() failed.\n"); return PVR_FAIL; } // offset the texture pointer by one mip-map level /* PVRTC case */ if ( bIsCompressedFormat ) { theTexturePtr += CompressedImageSize; } else { /* New formula that takes into account bit counts inferior to 8 (e.g. 1 bpp) */ theTexturePtr += (nSizeX * nSizeY * psPVRHeader->dwBitCount + 7) / 8; } } } *texName = textureName; if(psTextureHeader) { *(PVR_Texture_Header*)psTextureHeader = *psPVRHeader; ((PVR_Texture_Header*)psTextureHeader)->dwPVR = PVRTEX_IDENTIFIER; ((PVR_Texture_Header*)psTextureHeader)->dwNumSurfs = u32NumSurfs; } if(eTextureType==GL_FLOAT || eTextureType==GL_HALF_FLOAT_OES) { if(!psPVRHeader->dwMipMapCount) { // Texture filter modes are limited to these for float textures glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } else { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } } else { if(!psPVRHeader->dwMipMapCount) { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(eTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(eTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } } if( (psPVRHeader->dwWidth & (psPVRHeader->dwWidth - 1)) | (psPVRHeader->dwHeight & (psPVRHeader->dwHeight - 1))) { /* NPOT textures requires the wrap mode to be set explicitly to GL_CLAMP_TO_EDGE or the texture will be inconsistent. */ glTexParameteri(eTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(eTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } return PVR_SUCCESS; }
int dump_tex(int argc, const char * argv[]) { TexFile tex; FileStream inStream; FileStream outStream; if (!inStream.open(argv[0], "rb")) { printf("Error input file %s\n", argv[0]); return 1; } /* if (!outStream.open(argv[1], "wb")) { printf("Error output file %s\n", argv[1]); return 1; }*/ if (!tex.read(&inStream)) { printf("Error input file %s\n", argv[0]); return 1; } // Dump the raw rgb unsigned int size = tex.mHeader.size * tex.mHeader.size * 4; unsigned char *outputData = (unsigned char *)malloc(size); int result = 0; int actualSize = 0; const char *fmt = "UNKN"; bool hasMips = tex.mHeader.flags & 0x20; if (tex.mHeader.unknown0[1] == 11 || tex.mHeader.unknown0[1] == 13) // PVRTC { unsigned int bytes = PVRTDecompressPVRTC(tex.mData, 0, tex.mHeader.size, tex.mHeader.size, outputData); result = stbi_write_tga(argv[1], tex.mHeader.size, tex.mHeader.size, STBI_rgb_alpha, outputData); fmt = "PVRTC"; actualSize = ( std::max((int)tex.mHeader.size, 8) * std::max((int)tex.mHeader.size, 8) * 4 + 7) / 8; } else if (tex.mHeader.unknown0[1] == 1) // RGBA { memcpy(outputData, tex.mData, tex.mHeader.size*tex.mHeader.size*4); //result = stbi_write_tga(argv[1], tex.mHeader.size, tex.mHeader.size, STBI_rgb_alpha, outputData); fmt = "RGBA"; actualSize = tex.mHeader.size*tex.mHeader.size*4; } else if (tex.mHeader.unknown0[1] == 0) // RGB { memcpy(outputData, tex.mData, tex.mHeader.size*tex.mHeader.size*3); //result = stbi_write_tga(argv[1], tex.mHeader.size, tex.mHeader.size, STBI_rgb, outputData); fmt = "RGB "; actualSize = tex.mHeader.size*tex.mHeader.size*3; } else if (tex.mHeader.unknown0[1] == 6) // RGBA5551 { unsigned short *in = (unsigned short*)tex.mData; unsigned char *out = outputData; for (int i=0; i<tex.mHeader.size*tex.mHeader.size; i++) { unsigned short alpha_mask = 0x800; unsigned short red_mask = 0x7C00; unsigned short green_mask = 0x3E0; unsigned short blue_mask = 0x1F; unsigned short inv = *in; inv >>= 1; *out++ = (inv & blue_mask) << 3; *out++ = ((inv & green_mask) >> 5) << 3; *out++ = ((inv & red_mask) >> 10) << 3; *out++ = (*in & 0x1) ? 255 : 0; in++; } //result = stbi_write_tga(argv[1], tex.mHeader.size, tex.mHeader.size, STBI_rgb_alpha, outputData); fmt = "5551"; actualSize = tex.mHeader.size*tex.mHeader.size*2; }
ImageWidget(const QString& fileName, const QString& title, QWidget* parent = 0) : QWidget(parent), title_(title) { if (isBrushSet_ == false) { QImage brushImage(64, 64, QImage::Format_RGB32); for (int y = 0; y < 64; ++y) for (int x = 0; x < 64; ++x) { int u = x / 32; int v = y / 32; int b = (u ^ v) & 1; brushImage.setPixel(QPoint(x, y), b ? 0xb0b0b0 : 0xe0e0e0); } brush_ = QBrush(brushImage); isBrushSet_ = true; } QFileInfo fileInfo(fileName); #if 0 // we drop support for pvrt if (fileInfo.suffix().toLower() == "pvr") { CPVRTResourceFile file(qPrintable(fileName)); if (file.IsOpen() == true && file.Size() >= sizeof(PVR_Texture_Header)) { PVR_Texture_Header* header = (PVR_Texture_Header*)file.DataPtr(); int width = header->dwWidth; int height = header->dwHeight; PVRTuint32 pixelType = header->dwpfFlags & PVRTEX_PIXELTYPE; if (pixelType == OGL_PVRTC2 || pixelType == OGL_PVRTC4) { void* ptr = (char*)file.DataPtr() + header->dwHeaderSize; unsigned char* resultImage = (unsigned char*)malloc(width * height * 4); PVRTDecompressPVRTC(ptr, pixelType == OGL_PVRTC2, width, height, resultImage); image_ = QImage(width, height, QImage::Format_ARGB32); for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) { int index = (x + y * width) * 4; unsigned char r = resultImage[index + 0]; unsigned char g = resultImage[index + 1]; unsigned char b = resultImage[index + 2]; unsigned char a = resultImage[index + 3]; image_.setPixel(x, y, qRgba(r, g, b, a)); } free(resultImage); } } } else #endif image_.load(fileName); if (image_.width() > 0 && image_.height() > 0) { info_ = QString("%1x%2").arg(QString::number(image_.width()), QString::number(image_.height())); } }