/*!*************************************************************************** @Function Print3D @Input fPosX X Position @Input fPosY Y Position @Input fScale Text scale @Input Colour ARGB colour @Input UTF32 Array of UTF32 characters @Input bUpdate Whether to update the vertices @Return EPVRTError Success of failure @Description Takes an array of UTF32 characters and generates the required mesh. *****************************************************************************/ EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const CPVRTArray<PVRTuint32>& UTF32, bool bUpdate) { // No textures! so... no window if (!m_bTexturesSet) { PVRTErrorOutputDebug("DisplayWindow : You must call CPVRTPrint3D::SetTextures(...) before using this function.\n"); return PVR_FAIL; } // nothing to be drawn if(UTF32.GetSize() == 0) return PVR_FAIL; // Adjust input parameters if(!m_bUsingProjection) { fPosX = (float)((int)(fPosX * (640.0f/100.0f))); fPosY = -(float)((int)(fPosY * (480.0f/100.0f))); } // Create Vertex Buffer (only if it doesn't exist) if(m_pPrint3dVtx == 0) { m_pPrint3dVtx = (SPVRTPrint3DAPIVertex*)malloc(MAX_LETTERS*4*sizeof(SPVRTPrint3DAPIVertex)); if(!m_pPrint3dVtx) return PVR_FAIL; } // Fill up our buffer if(bUpdate) m_nCachedNumVerts = UpdateLine(0.0f, fPosX, fPosY, fScale, Colour, UTF32, m_pPrint3dVtx); // Draw the text if(!DrawLine(m_pPrint3dVtx, m_nCachedNumVerts)) return PVR_FAIL; return PVR_SUCCESS; }
/*!*************************************************************************** @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 PVRTPrint3D @Input fPosX Position of the text along X @Input fPosY Position of the text along Y @Input fScale Scale of the text @Input Colour Colour of the text @Input pszFormat Format string for the text @Return PVR_SUCCESS or PVR_FAIL @Description Display 3D text on screen. No window needs to be allocated to use this function. However, CPVRTPrint3D::SetTextures(...) must have been called beforehand. This function accepts formatting in the printf way. *****************************************************************************/ EPVRTError CPVRTPrint3D::Print3D(float fPosX, float fPosY, const float fScale, unsigned int Colour, const char * const pszFormat, ...) { #if !defined (DISABLE_PRINT3D) va_list args; static char Text[MAX_LETTERS+1], sPreviousString[MAX_LETTERS+1]; static float XPosPrev, YPosPrev, fScalePrev; static unsigned int ColourPrev; static unsigned int nVertices; // No textures! so... no window if (!m_bTexturesSet) { PVRTErrorOutputDebug("DisplayWindow : You must call CPVRTPrint3D::SetTextures(...) before using this function.\n"); return PVR_FAIL; } // Reading the arguments to create our Text string va_start(args, pszFormat); #if defined(__SYMBIAN32__) || defined(UITRON) || defined(_UITRON_) vsprintf(Text, pszFormat, args); #else vsnprintf(Text, MAX_LETTERS+1, pszFormat, args); #endif va_end(args); // nothing to be drawn if(*Text == 0) return PVR_FAIL; // Adjust input parameters if(!m_bUsingProjection) { fPosX *= 640.0f/100.0f; fPosY *= 480.0f/100.0f; } // We check if the string has been changed since last time if( strcmp (sPreviousString, Text) != 0 || fPosX != XPosPrev || fPosY != YPosPrev || fScale != fScalePrev || Colour != ColourPrev || m_pPrint3dVtx == NULL) { // copy strings strcpy (sPreviousString, Text); XPosPrev = fPosX; YPosPrev = fPosY; fScalePrev = fScale; ColourPrev = Colour; // Create Vertex Buffer (only if it doesn't exist) if(m_pPrint3dVtx == 0) { m_pPrint3dVtx = (SPVRTPrint3DAPIVertex*)malloc(MAX_LETTERS*4*sizeof(SPVRTPrint3DAPIVertex)); if(!m_pPrint3dVtx) return PVR_FAIL; } // Fill up our buffer nVertices = UpdateLine(0, 0.0f, fPosX, fPosY, fScale, Colour, Text, m_pPrint3dVtx); } // Draw the text DrawLineUP(m_pPrint3dVtx, nVertices); #endif return PVR_SUCCESS; }
/*!*************************************************************************** @Function DisplayWindow @Input dwWin @Return PVR_SUCCESS or PVR_FAIL @Description Display window. This function MUST be called between a BeginScene/EndScene pair as it uses D3D render primitive calls. CPVRTPrint3D::SetTextures(...) must have been called beforehand. *****************************************************************************/ EPVRTError CPVRTPrint3D::DisplayWindow(unsigned int dwWin) { #if !defined (DISABLE_PRINT3D) unsigned int i; float fTitleSize = 0.0f; // No textures! so... no window if (!m_bTexturesSet) { PVRTErrorOutputDebug("DisplayWindow : You must call PVRTPrint3D::SetTextures(...) before using this function.\n"); return PVR_FAIL; } // Update Vertex data only when needed if(m_pWin[dwWin].bNeedUpdated) { // TITLE if(m_pWin[dwWin].dwFlags & Print3D_WIN_TITLE) { // Set title size if(m_pWin[dwWin].fTitleFontSize < 0.0f) fTitleSize = 8.0f + 16.0f; else fTitleSize = m_pWin[dwWin].fTitleFontSize * 23.5f + 16.0f; // Title UpdateTitleVertexBuffer(dwWin); // Background if (!(m_pWin[dwWin].dwFlags & Print3D_FULL_TRANS)) { // Draw title background UpdateBackgroundWindow( dwWin, m_pWin[dwWin].dwTitleBaseColor, 0.0f, m_pWin[dwWin].fWinPos[0], m_pWin[dwWin].fWinPos[1], m_pWin[dwWin].fWinSize[0], fTitleSize, &m_pWin[dwWin].pWindowVtxTitle); } } // Main text UpdateMainTextVertexBuffer(dwWin); UpdateBackgroundWindow( dwWin, m_pWin[dwWin].dwWinBaseColor, 0.0f, m_pWin[dwWin].fWinPos[0], (m_pWin[dwWin].fWinPos[1] + fTitleSize), m_pWin[dwWin].fWinSize[0], m_pWin[dwWin].fWinSize[1], &m_pWin[dwWin].pWindowVtxText); // Don't update until next change makes it needed m_pWin[dwWin].bNeedUpdated = false; } // Ensure any previously drawn text has been submitted before drawing the window. Flush(); // Save current render states APIRenderStates(0); // DRAW TITLE if(m_pWin[dwWin].dwFlags & Print3D_WIN_TITLE) { if (!(m_pWin[dwWin].dwFlags & Print3D_FULL_TRANS)) { DrawBackgroundWindowUP(m_pWin[dwWin].pWindowVtxTitle, (m_pWin[dwWin].dwFlags & Print3D_FULL_OPAQUE) ? true : false, (m_pWin[dwWin].dwFlags & Print3D_NO_BORDER) ? false : true); } // Left and Right text DrawLineUP(m_pWin[dwWin].pTitleVtxL, m_pWin[dwWin].nTitleVerticesL); DrawLineUP(m_pWin[dwWin].pTitleVtxR, m_pWin[dwWin].nTitleVerticesR); } // DRAW WINDOW if (m_pWin[dwWin].dwFlags & Print3D_WIN_ACTIVE) { // Background if (!(m_pWin[dwWin].dwFlags & Print3D_FULL_TRANS)) { DrawBackgroundWindowUP(m_pWin[dwWin].pWindowVtxText, (m_pWin[dwWin].dwFlags & Print3D_FULL_OPAQUE) ? true : false, (m_pWin[dwWin].dwFlags & Print3D_NO_BORDER) ? false : true); } // Text, line by line for (i=0; i<m_pWin[dwWin].dwBufferSizeY; i++) { DrawLineUP(m_pWin[dwWin].pLineVtx[i], m_pWin[dwWin].nLineVertices[i]); } } // Restore render states APIRenderStates(1); #endif return PVR_SUCCESS; }
/*!*************************************************************************** @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; }