| /****************************************************************************** |
| |
| @File OGLES2/PVRTTextureAPI.cpp |
| |
| @Title OGLES2/PVRTTextureAPI |
| |
| @Version |
| |
| @Copyright Copyright (c) Imagination Technologies Limited. |
| |
| @Platform ANSI compatible |
| |
| @Description OGLES2 texture loading. |
| |
| ******************************************************************************/ |
| |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "PVRTContext.h" |
| #include "PVRTgles2Ext.h" |
| #include "PVRTTexture.h" |
| #include "PVRTTextureAPI.h" |
| #include "PVRTDecompress.h" |
| #include "PVRTFixedPoint.h" |
| #include "PVRTMap.h" |
| #include "PVRTMatrix.h" |
| #include "PVRTMisc.h" |
| #include "PVRTResourceFile.h" |
| |
| /***************************************************************************** |
| ** Functions |
| ****************************************************************************/ |
| |
| |
| /*!*********************************************************************** |
| @Function: PVRTGetOGLESTextureFormat |
| @Input: sTextureHeader |
| @Modified: internalformat |
| @Modified: format |
| @Modified: type |
| @Description: Gets the OpenGLES equivalent values of internal format, |
| format and type for this texture header. This will return |
| any supported OpenGLES texture values, it is up to the user |
| to decide if these are valid for their current platform. |
| *************************************************************************/ |
| static const void PVRTGetOGLES2TextureFormat(const PVRTextureHeaderV3& sTextureHeader, PVRTuint32& internalformat, PVRTuint32& format, PVRTuint32& type) |
| { |
| PVRTuint64 PixelFormat = sTextureHeader.u64PixelFormat; |
| EPVRTVariableType ChannelType = (EPVRTVariableType)sTextureHeader.u32ChannelType; |
| |
| //Initialisation. Any invalid formats will return 0 always. |
| format = 0; |
| type = 0; |
| internalformat=0; |
| |
| //Get the last 32 bits of the pixel format. |
| PVRTuint64 PixelFormatPartHigh = PixelFormat&PVRTEX_PFHIGHMASK; |
| |
| //Check for a compressed format (The first 8 bytes will be 0, so the whole thing will be equal to the last 32 bits). |
| if (PixelFormatPartHigh==0) |
| { |
| //Format and type == 0 for compressed textures. |
| switch (PixelFormat) |
| { |
| case ePVRTPF_PVRTCI_2bpp_RGB: |
| { |
| internalformat=GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; |
| return; |
| } |
| case ePVRTPF_PVRTCI_2bpp_RGBA: |
| { |
| internalformat=GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; |
| return; |
| } |
| case ePVRTPF_PVRTCI_4bpp_RGB: |
| { |
| internalformat=GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; |
| return; |
| } |
| case ePVRTPF_PVRTCI_4bpp_RGBA: |
| { |
| internalformat=GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; |
| return; |
| } |
| #ifndef TARGET_OS_IPHONE |
| case ePVRTPF_PVRTCII_2bpp: |
| { |
| internalformat=GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG; |
| return; |
| } |
| case ePVRTPF_PVRTCII_4bpp: |
| { |
| internalformat=GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG; |
| return; |
| } |
| case ePVRTPF_ETC1: |
| { |
| internalformat=GL_ETC1_RGB8_OES; |
| return; |
| } |
| #endif |
| default: |
| return; |
| } |
| } |
| else |
| { |
| switch (ChannelType) |
| { |
| case ePVRTVarTypeFloat: |
| { |
| switch (PixelFormat) |
| { |
| //HALF_FLOAT_OES |
| case PVRTGENPIXELID4('r','g','b','a',16,16,16,16): |
| { |
| type=GL_HALF_FLOAT_OES; |
| format = GL_RGBA; |
| internalformat=GL_RGBA; |
| return; |
| } |
| case PVRTGENPIXELID3('r','g','b',16,16,16): |
| { |
| type=GL_HALF_FLOAT_OES; |
| format = GL_RGB; |
| internalformat=GL_RGB; |
| return; |
| } |
| case PVRTGENPIXELID2('l','a',16,16): |
| { |
| type=GL_HALF_FLOAT_OES; |
| format = GL_LUMINANCE_ALPHA; |
| internalformat=GL_LUMINANCE_ALPHA; |
| return; |
| } |
| case PVRTGENPIXELID1('l',16): |
| { |
| type=GL_HALF_FLOAT_OES; |
| format = GL_LUMINANCE; |
| internalformat=GL_LUMINANCE; |
| return; |
| } |
| case PVRTGENPIXELID1('a',16): |
| { |
| type=GL_HALF_FLOAT_OES; |
| format = GL_ALPHA; |
| internalformat=GL_ALPHA; |
| return; |
| } |
| //FLOAT (OES) |
| case PVRTGENPIXELID4('r','g','b','a',32,32,32,32): |
| { |
| type=GL_FLOAT; |
| format = GL_RGBA; |
| internalformat=GL_RGBA; |
| return; |
| } |
| case PVRTGENPIXELID3('r','g','b',32,32,32): |
| { |
| type=GL_FLOAT; |
| format = GL_RGB; |
| internalformat=GL_RGB; |
| return; |
| } |
| case PVRTGENPIXELID2('l','a',32,32): |
| { |
| type=GL_FLOAT; |
| format = GL_LUMINANCE_ALPHA; |
| internalformat=GL_LUMINANCE_ALPHA; |
| return; |
| } |
| case PVRTGENPIXELID1('l',32): |
| { |
| type=GL_FLOAT; |
| format = GL_LUMINANCE; |
| internalformat=GL_LUMINANCE; |
| return; |
| } |
| case PVRTGENPIXELID1('a',32): |
| { |
| type=GL_FLOAT; |
| format = GL_ALPHA; |
| internalformat=GL_ALPHA; |
| return; |
| } |
| } |
| break; |
| } |
| case ePVRTVarTypeUnsignedByteNorm: |
| { |
| type = GL_UNSIGNED_BYTE; |
| switch (PixelFormat) |
| { |
| case PVRTGENPIXELID4('r','g','b','a',8,8,8,8): |
| { |
| format = internalformat = GL_RGBA; |
| return; |
| } |
| case PVRTGENPIXELID3('r','g','b',8,8,8): |
| { |
| format = internalformat = GL_RGB; |
| return; |
| } |
| case PVRTGENPIXELID2('l','a',8,8): |
| { |
| format = internalformat = GL_LUMINANCE_ALPHA; |
| return; |
| } |
| case PVRTGENPIXELID1('l',8): |
| { |
| format = internalformat = GL_LUMINANCE; |
| return; |
| } |
| case PVRTGENPIXELID1('a',8): |
| { |
| format = internalformat = GL_ALPHA; |
| return; |
| } |
| case PVRTGENPIXELID4('b','g','r','a',8,8,8,8): |
| { |
| format = internalformat = GL_BGRA; |
| return; |
| } |
| } |
| break; |
| } |
| case ePVRTVarTypeUnsignedShortNorm: |
| { |
| switch (PixelFormat) |
| { |
| case PVRTGENPIXELID4('r','g','b','a',4,4,4,4): |
| { |
| type = GL_UNSIGNED_SHORT_4_4_4_4; |
| format = internalformat = GL_RGBA; |
| return; |
| } |
| case PVRTGENPIXELID4('r','g','b','a',5,5,5,1): |
| { |
| type = GL_UNSIGNED_SHORT_5_5_5_1; |
| format = internalformat = GL_RGBA; |
| return; |
| } |
| case PVRTGENPIXELID3('r','g','b',5,6,5): |
| { |
| type = GL_UNSIGNED_SHORT_5_6_5; |
| format = internalformat = GL_RGB; |
| return; |
| } |
| } |
| break; |
| } |
| default: |
| return; |
| } |
| } |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTTextureTile |
| @Modified pOut The tiled texture in system memory |
| @Input pIn The source texture |
| @Input nRepeatCnt Number of times to repeat the source texture |
| @Description Allocates and fills, in system memory, a texture large enough |
| to repeat the source texture specified number of times. |
| *****************************************************************************/ |
| void PVRTTextureTile( |
| PVRTextureHeaderV3 **pOut, |
| const PVRTextureHeaderV3 * const pIn, |
| const int nRepeatCnt) |
| { |
| unsigned int nFormat = 0, nType = 0, nBPP, nSize, nElW = 0, nElH = 0, nElD = 0; |
| PVRTuint8 *pMmSrc, *pMmDst; |
| unsigned int nLevel; |
| PVRTextureHeaderV3 *psTexHeaderNew; |
| |
| _ASSERT(pIn->u32Width); |
| _ASSERT(pIn->u32Width == pIn->u32Height); |
| _ASSERT(nRepeatCnt > 1); |
| |
| PVRTGetOGLES2TextureFormat(*pIn,nFormat,nFormat,nType); |
| PVRTGetFormatMinDims(pIn->u64PixelFormat,nElW,nElH,nElD); |
| |
| nBPP = PVRTGetBitsPerPixel(pIn->u64PixelFormat); |
| nSize = pIn->u32Width * nRepeatCnt; |
| |
| psTexHeaderNew = PVRTTextureCreate(nSize, nSize, nElW, nElH, nBPP, true); |
| *psTexHeaderNew = *pIn; |
| pMmDst = (PVRTuint8*)psTexHeaderNew + sizeof(*psTexHeaderNew); |
| pMmSrc = (PVRTuint8*)pIn + sizeof(*pIn); |
| |
| for(nLevel = 0; ((unsigned int)1 << nLevel) < nSize; ++nLevel) |
| { |
| int nBlocksDstW = PVRT_MAX((unsigned int)1, (nSize >> nLevel) / nElW); |
| int nBlocksDstH = PVRT_MAX((unsigned int)1, (nSize >> nLevel) / nElH); |
| int nBlocksSrcW = PVRT_MAX((unsigned int)1, (pIn->u32Width >> nLevel) / nElW); |
| int nBlocksSrcH = PVRT_MAX((unsigned int)1, (pIn->u32Height >> nLevel) / nElH); |
| int nBlocksS = nBPP * nElW * nElH / 8; |
| |
| PVRTTextureLoadTiled( |
| pMmDst, |
| nBlocksDstW, |
| nBlocksDstH, |
| pMmSrc, |
| nBlocksSrcW, |
| nBlocksSrcH, |
| nBlocksS, |
| (/*pIn->u64PixelFormat>=ePVRTPF_PVRTCI_2bpp_RGB &&*/ pIn->u64PixelFormat<=ePVRTPF_PVRTCI_4bpp_RGBA) ? true : false); |
| |
| pMmDst += nBlocksDstW * nBlocksDstH * nBlocksS; |
| pMmSrc += nBlocksSrcW * nBlocksSrcH * nBlocksS; |
| } |
| |
| psTexHeaderNew->u32Width = nSize; |
| psTexHeaderNew->u32Height = nSize; |
| psTexHeaderNew->u32MIPMapCount = nLevel+1; |
| *pOut = psTexHeaderNew; |
| } |
| |
| /*!*************************************************************************** |
| @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; |
| |
| CPVRTgles2Ext extensions; |
| extensions.LoadExtensions(); |
| |
| //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. |
| PVRTGetOGLES2TextureFormat(sTextureHeader,eTextureInternalFormat,eTextureFormat,eTextureType); |
| |
| //Check supported texture formats. |
| bool bIsPVRTCSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_compression_pvrtc"); |
| bool bIsPVRTC2Supported = CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_texture_compression_pvrtc2"); |
| #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"); |
| bool bIsTexture3DSupported = CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_texture_3D"); |
| #ifndef TARGET_OS_IPHONE |
| bool bIsETCSupported = CPVRTgles2Ext::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, but all faces. |
| 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; |
| } |
| } |
| } |
| #ifndef TARGET_OS_IPHONE //TODO |
| else if (eTextureInternalFormat==GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG || eTextureInternalFormat==GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG) |
| { |
| //Check for PVRTCI support. |
| if(bIsPVRTC2Supported) |
| { |
| bIsCompressedFormatSupported = bIsCompressedFormat = true; |
| } |
| else |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer error: PVRTC not supported.\n"); |
| return PVR_FAIL; |
| } |
| } |
| else if (eTextureInternalFormat==GL_ETC1_RGB8_OES) |
| { |
| if(bIsETCSupported) |
| { |
| bIsCompressedFormatSupported = bIsCompressedFormat = true; |
| } |
| else |
| { |
| if(bAllowDecompress) |
| { |
| //Output a warning. |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer warning: ETC not supported. Converting to RGBA8888 instead.\n"); |
| |
| //Modify boolean values. |
| bIsCompressedFormatSupported = false; |
| bIsCompressedFormat = true; |
| |
| //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. OGLES1, 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. |
| PVRTDecompressETC(pTempCompData,uiMIPWidth,uiMIPHeight,pTempDecompData,0); |
| |
| //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. |
| PVRTDecompressETC(pTempCompData,uiMIPWidth,uiMIPHeight,pTempDecompData,0); |
| |
| //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: ETC not supported.\n"); |
| return PVR_FAIL; |
| } |
| } |
| } |
| #endif |
| } |
| |
| //Check for BGRA support. |
| if(eTextureFormat==GL_BGRA) |
| { |
| #ifdef TARGET_OS_IPHONE |
| eTextureInternalFormat = GL_RGBA; |
| #endif |
| if(!bIsBGRA8888Supported) |
| { |
| #ifdef TARGET_OS_IPHONE |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_BGRA texture as extension GL_APPLE_texture_format_BGRA8888 is unsupported.\n"); |
| #else |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported.\n"); |
| #endif |
| return PVR_FAIL; |
| } |
| } |
| |
| //Check for floating point textures |
| if (eTextureType==GL_HALF_FLOAT_OES) |
| { |
| if(!bIsFloat16Supported) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_HALF_FLOAT_OES texture as extension GL_OES_texture_half_float is unsupported.\n"); |
| } |
| } |
| if (eTextureType==GL_FLOAT) |
| { |
| if(!bIsFloat32Supported) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Unable to load GL_FLOAT texture as extension GL_OES_texture_float is unsupported.\n"); |
| } |
| } |
| |
| //Deal with unsupported texture formats |
| if (eTextureInternalFormat==0) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: pixel type not supported.\n"); |
| return PVR_FAIL; |
| } |
| |
| //PVR files are never row aligned. |
| glPixelStorei(GL_UNPACK_ALIGNMENT,1); |
| |
| //Generate a texture |
| glGenTextures(1, texName); |
| |
| //Initialise a texture target. |
| GLint eTarget=GL_TEXTURE_2D; |
| |
| //A mix of arrays/cubes/depths are not permitted in OpenGL ES. Check. |
| if(sTextureHeader.u32NumFaces>1 || sTextureHeader.u32NumSurfaces>1 || sTextureHeader.u32Depth>1) |
| { |
| if((sTextureHeader.u32NumFaces>1) && (sTextureHeader.u32NumSurfaces>1)) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Arrays of cubemaps are not supported by OpenGL ES 3.0\n"); |
| return PVR_FAIL; |
| } |
| else if((sTextureHeader.u32NumFaces>1) && (sTextureHeader.u32Depth>1)) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: 3D Cubemap textures are not supported by OpenGL ES 3.0\n"); |
| return PVR_FAIL; |
| } |
| else if((sTextureHeader.u32NumSurfaces>1) && (sTextureHeader.u32Depth>1)) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: Arrays of 3D textures are not supported by OpenGL ES 3.0\n"); |
| return PVR_FAIL; |
| } |
| |
| if(sTextureHeader.u32NumSurfaces>1) |
| { |
| // GL_TEXTURE_2D_ARRAY; |
| return PVR_FAIL; |
| } |
| else if(sTextureHeader.u32NumFaces>1) |
| { |
| eTarget = GL_TEXTURE_CUBE_MAP; |
| } |
| else if(sTextureHeader.u32Depth>1) |
| { |
| eTarget = GL_TEXTURE_3D_OES; |
| bUsesTexImage3D = true; |
| } |
| } |
| |
| if(bUsesTexImage3D && !bIsTexture3DSupported) |
| { |
| return PVR_FAIL; |
| } |
| |
| //Bind the texture |
| glBindTexture(eTarget, *texName); |
| |
| if(glGetError()) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glBindTexture() failed.\n"); |
| return PVR_FAIL; |
| } |
| |
| //Initialise the current MIP size. |
| PVRTuint32 uiCurrentMIPSize=0; |
| |
| //Loop through the faces |
| //Check if this is a cube map. |
| if(sTextureHeader.u32NumFaces>1) |
| { |
| eTarget=GL_TEXTURE_CUBE_MAP_POSITIVE_X; |
| } |
| |
| //Initialise the width/height |
| PVRTuint32 u32MIPWidth = sTextureHeader.u32Width; |
| PVRTuint32 u32MIPHeight = sTextureHeader.u32Height; |
| |
| //Temporary data to save on if statements within the load loops. |
| PVRTuint8* pTempData=NULL; |
| PVRTextureHeaderV3 *psTempHeader=NULL; |
| if (bIsCompressedFormat && !bIsCompressedFormatSupported) |
| { |
| pTempData=(PVRTuint8*)pDecompressedData; |
| psTempHeader=&sTextureHeaderDecomp; |
| } |
| else |
| { |
| pTempData=pTextureData; |
| psTempHeader=&sTextureHeader; |
| } |
| |
| PVRTuint32 u32MIPDepth = 1; |
| if(bUsesTexImage3D) |
| { |
| if(psTempHeader->u32Depth>1) |
| { |
| u32MIPDepth = psTempHeader->u32Depth; //3d texture. |
| } |
| else |
| { |
| return PVR_FAIL; //2d arrays. |
| } |
| } |
| |
| //Loop through all MIP levels. |
| if (bIsLegacyPVR) |
| { |
| //Temporary texture target. |
| GLint eTextureTarget=eTarget; |
| |
| //Loop through all the faces. |
| for (PVRTuint32 uiFace=0; uiFace<psTempHeader->u32NumFaces; ++uiFace) |
| { |
| //Loop through all the mip levels. |
| for (PVRTuint32 uiMIPLevel=0; uiMIPLevel<psTempHeader->u32MIPMapCount; ++uiMIPLevel) |
| { |
| //Get the current MIP size. |
| uiCurrentMIPSize=PVRTGetTextureDataSize(*psTempHeader,uiMIPLevel,false,false); |
| |
| if (uiMIPLevel>=nLoadFromLevel) |
| { |
| //Upload the texture |
| if(bUsesTexImage3D) |
| { |
| if(bIsCompressedFormat && bIsCompressedFormatSupported) |
| { |
| extensions.glCompressedTexImage3DOES(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, u32MIPDepth, 0, uiCurrentMIPSize, pTempData); |
| } |
| else |
| { |
| extensions.glTexImage3DOES(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, u32MIPDepth, 0, eTextureFormat, eTextureType, pTempData); |
| } |
| } |
| else |
| { |
| if(bIsCompressedFormat && bIsCompressedFormatSupported) |
| { |
| glCompressedTexImage2D(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, 0, uiCurrentMIPSize, pTempData); |
| } |
| else |
| { |
| glTexImage2D(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, 0, eTextureFormat, eTextureType, pTempData); |
| } |
| } |
| } |
| pTempData+=uiCurrentMIPSize; |
| |
| //Reduce the MIP Size. |
| u32MIPWidth=PVRT_MAX(1,u32MIPWidth>>1); |
| u32MIPHeight=PVRT_MAX(1,u32MIPHeight>>1); |
| } |
| |
| //Increase the texture target. |
| eTextureTarget++; |
| |
| //Reset the current MIP dimensions. |
| u32MIPWidth=psTempHeader->u32Width; |
| u32MIPHeight=psTempHeader->u32Height; |
| |
| //Error check |
| if(glGetError()) |
| { |
| FREE(pDecompressedData); |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexImage2D() failed.\n"); |
| return PVR_FAIL; |
| } |
| } |
| } |
| else |
| { |
| for (PVRTuint32 uiMIPLevel=0; uiMIPLevel<psTempHeader->u32MIPMapCount; ++uiMIPLevel) |
| { |
| //Get the current MIP size. |
| uiCurrentMIPSize=PVRTGetTextureDataSize(*psTempHeader,uiMIPLevel,false,false); |
| |
| GLint eTextureTarget=eTarget; |
| |
| for (PVRTuint32 uiFace=0; uiFace<psTempHeader->u32NumFaces; ++uiFace) |
| { |
| if (uiMIPLevel>=nLoadFromLevel) |
| { |
| //Upload the texture |
| if(bUsesTexImage3D) |
| { |
| //Upload the texture |
| if(bIsCompressedFormat && bIsCompressedFormatSupported) |
| { |
| extensions.glCompressedTexImage3DOES(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, u32MIPDepth, 0, uiCurrentMIPSize, pTempData); |
| } |
| else |
| { |
| extensions.glTexImage3DOES(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, u32MIPDepth, 0, eTextureFormat, eTextureType, pTempData); |
| } |
| } |
| else |
| { |
| //Upload the texture |
| if(bIsCompressedFormat && bIsCompressedFormatSupported) |
| { |
| glCompressedTexImage2D(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, 0, uiCurrentMIPSize, pTempData); |
| } |
| else |
| { |
| glTexImage2D(eTextureTarget, uiMIPLevel - nLoadFromLevel, eTextureInternalFormat, u32MIPWidth, u32MIPHeight, 0, eTextureFormat, eTextureType, pTempData); |
| } |
| } |
| } |
| pTempData+=uiCurrentMIPSize; |
| eTextureTarget++; |
| } |
| |
| //Reduce the MIP Size. |
| u32MIPWidth=PVRT_MAX(1,u32MIPWidth>>1); |
| u32MIPHeight=PVRT_MAX(1,u32MIPHeight>>1); |
| |
| //Error check |
| if(glGetError()) |
| { |
| FREE(pDecompressedData); |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexImage2D() failed.\n"); |
| return PVR_FAIL; |
| } |
| } |
| } |
| |
| FREE(pDecompressedData); |
| |
| if (eTarget!=GL_TEXTURE_2D) |
| { |
| eTarget=GL_TEXTURE_CUBE_MAP; |
| } |
| |
| //Error check |
| if(glGetError()) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexImage2D() failed.\n"); |
| return PVR_FAIL; |
| } |
| |
| //Set Minification and Magnification filters according to whether MIP maps are present. |
| if(eTextureType==GL_FLOAT || eTextureType==GL_HALF_FLOAT_OES) |
| { |
| if(sTextureHeader.u32MIPMapCount==1) |
| { // 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(sTextureHeader.u32MIPMapCount==1) |
| { |
| 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( (sTextureHeader.u32Width & (sTextureHeader.u32Width - 1)) | (sTextureHeader.u32Height & (sTextureHeader.u32Height - 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(eTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); |
| glTexParameteri(eTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); |
| } |
| |
| //Error check |
| if(glGetError()) |
| { |
| PVRTErrorOutputDebug("PVRTTextureLoadFromPointer failed: glTexParameter() failed.\n"); |
| return PVR_FAIL; |
| } |
| |
| return PVR_SUCCESS; |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTTextureLoadFromPVR |
| @Input filename Filename of the .PVR file to load the texture from |
| @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) |
| @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 binary PVR files and loaded in. Can load parts of a |
| mip mapped texture (i.e. skipping the highest detailed levels). |
| Sets the texture MIN/MAG filter to GL_LINEAR_MIPMAP_NEAREST/GL_LINEAR |
| if mip maps are present, GL_LINEAR/GL_LINEAR otherwise. |
| *****************************************************************************/ |
| EPVRTError PVRTTextureLoadFromPVR( const char * const filename, |
| GLuint * const texName, |
| const void *psTextureHeader, |
| bool bAllowDecompress, |
| const unsigned int nLoadFromLevel, |
| CPVRTMap<unsigned int, CPVRTMap<unsigned int, MetaDataBlock> > *pMetaData) |
| { |
| //Attempt to open file. |
| CPVRTResourceFile TexFile(filename); |
| |
| //Check file opened successfully. |
| if (!TexFile.IsOpen()) |
| { |
| return PVR_FAIL; |
| } |
| |
| //Header size. |
| PVRTuint32 u32HeaderSize=0; |
| |
| //Boolean whether to byte swap the texture data or not. |
| bool bSwapDataEndianness=false; |
| |
| //Texture header to check against. |
| PVRTextureHeaderV3 sTextureHeader; |
| |
| //The channel type for endian swapping. |
| EPVRTVariableType u32CurrentChannelType=ePVRTVarTypeUnsignedByte; |
| |
| //Check the first word of the file and see if it's equal to the current identifier (or reverse identifier) |
| if(*(PVRTuint32*)TexFile.DataPtr()!=PVRTEX_CURR_IDENT && *(PVRTuint32*)TexFile.DataPtr()!=PVRTEX_CURR_IDENT_REV) |
| { |
| //Swap the header bytes if necessary. |
| if(!PVRTIsLittleEndian()) |
| { |
| bSwapDataEndianness=true; |
| PVRTuint32 u32HeaderSize=PVRTByteSwap32(*(PVRTuint32*)TexFile.DataPtr()); |
| |
| for (PVRTuint32 i=0; i<u32HeaderSize; ++i) |
| { |
| PVRTByteSwap( (PVRTuint8*)( ( (PVRTuint32*)TexFile.DataPtr() )+i),sizeof(PVRTuint32) ); |
| } |
| } |
| |
| //Get a pointer to the header. |
| PVR_Texture_Header* sLegacyTextureHeader=(PVR_Texture_Header*)TexFile.DataPtr(); |
| |
| //Set the header size. |
| u32HeaderSize=sLegacyTextureHeader->dwHeaderSize; |
| |
| //We only really need the channel type. |
| PVRTuint64 tempFormat; |
| EPVRTColourSpace tempColourSpace; |
| bool tempIsPreMult; |
| |
| //Map the enum to get the channel type. |
| PVRTMapLegacyTextureEnumToNewFormat( (PVRTPixelType)( sLegacyTextureHeader->dwpfFlags&0xff),tempFormat,tempColourSpace, u32CurrentChannelType, tempIsPreMult); |
| } |
| // If the header file has a reverse identifier, then we need to swap endianness |
| else if(*(PVRTuint32*)TexFile.DataPtr()==PVRTEX_CURR_IDENT_REV) |
| { |
| //Setup the texture header |
| sTextureHeader=*(PVRTextureHeaderV3*)TexFile.DataPtr(); |
| |
| bSwapDataEndianness=true; |
| PVRTextureHeaderV3* pTextureHeader=(PVRTextureHeaderV3*)TexFile.DataPtr(); |
| |
| pTextureHeader->u32ChannelType=PVRTByteSwap32(pTextureHeader->u32ChannelType); |
| pTextureHeader->u32ColourSpace=PVRTByteSwap32(pTextureHeader->u32ColourSpace); |
| pTextureHeader->u32Depth=PVRTByteSwap32(pTextureHeader->u32Depth); |
| pTextureHeader->u32Flags=PVRTByteSwap32(pTextureHeader->u32Flags); |
| pTextureHeader->u32Height=PVRTByteSwap32(pTextureHeader->u32Height); |
| pTextureHeader->u32MetaDataSize=PVRTByteSwap32(pTextureHeader->u32MetaDataSize); |
| pTextureHeader->u32MIPMapCount=PVRTByteSwap32(pTextureHeader->u32MIPMapCount); |
| pTextureHeader->u32NumFaces=PVRTByteSwap32(pTextureHeader->u32NumFaces); |
| pTextureHeader->u32NumSurfaces=PVRTByteSwap32(pTextureHeader->u32NumSurfaces); |
| pTextureHeader->u32Version=PVRTByteSwap32(pTextureHeader->u32Version); |
| pTextureHeader->u32Width=PVRTByteSwap32(pTextureHeader->u32Width); |
| PVRTByteSwap((PVRTuint8*)&pTextureHeader->u64PixelFormat,sizeof(PVRTuint64)); |
| |
| //Channel type. |
| u32CurrentChannelType=(EPVRTVariableType)pTextureHeader->u32ChannelType; |
| |
| //Header size. |
| u32HeaderSize=PVRTEX3_HEADERSIZE+sTextureHeader.u32MetaDataSize; |
| } |
| else |
| { |
| //Header size. |
| u32HeaderSize=PVRTEX3_HEADERSIZE+sTextureHeader.u32MetaDataSize; |
| } |
| |
| // Convert the data if needed |
| if(bSwapDataEndianness) |
| { |
| //Get the size of the variables types. |
| PVRTuint32 ui32VariableSize=0; |
| switch(u32CurrentChannelType) |
| { |
| case ePVRTVarTypeFloat: |
| case ePVRTVarTypeUnsignedInteger: |
| case ePVRTVarTypeUnsignedIntegerNorm: |
| case ePVRTVarTypeSignedInteger: |
| case ePVRTVarTypeSignedIntegerNorm: |
| { |
| ui32VariableSize=4; |
| break; |
| } |
| case ePVRTVarTypeUnsignedShort: |
| case ePVRTVarTypeUnsignedShortNorm: |
| case ePVRTVarTypeSignedShort: |
| case ePVRTVarTypeSignedShortNorm: |
| { |
| ui32VariableSize=2; |
| break; |
| } |
| case ePVRTVarTypeUnsignedByte: |
| case ePVRTVarTypeUnsignedByteNorm: |
| case ePVRTVarTypeSignedByte: |
| case ePVRTVarTypeSignedByteNorm: |
| { |
| ui32VariableSize=1; |
| break; |
| } |
| default: |
| break; |
| } |
| |
| //If the size of the variable type is greater than 1, then we need to byte swap. |
| if (ui32VariableSize>1) |
| { |
| //Get the texture data. |
| PVRTuint8* pu8OrigData = ( (PVRTuint8*)TexFile.DataPtr() + u32HeaderSize); |
| |
| //Get the size of the texture data. |
| PVRTuint32 ui32TextureDataSize = PVRTGetTextureDataSize(sTextureHeader); |
| |
| //Loop through and byte swap all the data. It's swapped in place so no need to do anything special. |
| for(PVRTuint32 i = 0; i < ui32TextureDataSize; i+=ui32VariableSize) |
| { |
| PVRTByteSwap(pu8OrigData+i,ui32VariableSize); |
| } |
| } |
| } |
| |
| return PVRTTextureLoadFromPointer(TexFile.DataPtr(), texName, psTextureHeader, bAllowDecompress, nLoadFromLevel,NULL,pMetaData); |
| } |
| |
| /*!*************************************************************************** |
| @Function PVRTTextureFormatGetBPP |
| @Input nFormat |
| @Input nType |
| @Description Returns the bits per pixel (BPP) of the format. |
| *****************************************************************************/ |
| unsigned int PVRTTextureFormatGetBPP(const GLuint nFormat, const GLuint nType) |
| { |
| switch(nFormat) |
| { |
| case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: |
| case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: |
| return 2; |
| case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: |
| case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: |
| return 4; |
| case GL_UNSIGNED_BYTE: |
| switch(nType) |
| { |
| case GL_RGBA: |
| case GL_BGRA: |
| return 32; |
| } |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| switch(nType) |
| { |
| case GL_RGBA: |
| return 16; |
| } |
| } |
| |
| return 0xFFFFFFFF; |
| } |
| |
| /***************************************************************************** |
| End of file (PVRTTextureAPI.cpp) |
| *****************************************************************************/ |
| |