Esempio n. 1
0
/*!***************************************************************************
@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;
}
Esempio n. 2
0
/*!***************************************************************************
 @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;
				}
			}
		}
Esempio n. 3
0
/*!***************************************************************************
 @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;
}
Esempio n. 4
0
/*!***************************************************************************
 @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;
}
Esempio n. 5
0
/*!***************************************************************************
 @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;
}