/*!***********************************************************************
	@Function:		PVRTGetOGLES3TextureFormat
	@Input:			sTextureHeader
	@Modified:		glInternalFormat
	@Modified:		glFormat
	@Modified:		glType
	@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 PVRTGetOGLES3TextureFormat(const PVRTextureHeaderV3& sTextureHeader, PVRTuint32& glInternalFormat, PVRTuint32& glFormat, PVRTuint32& glType)
{	
	PVRTuint64 PixelFormat = sTextureHeader.u64PixelFormat;
	EPVRTVariableType ChannelType = (EPVRTVariableType)sTextureHeader.u32ChannelType;
	EPVRTColourSpace ColourSpace = (EPVRTColourSpace)sTextureHeader.u32ColourSpace;

	//Initialisation. Any invalid formats will return 0 always.
	glFormat = 0;
	glType = 0;
	glInternalFormat=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:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
				}
				return;
			}
		case ePVRTPF_PVRTCI_2bpp_RGBA:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
				}
				return;
			}
		case ePVRTPF_PVRTCI_4bpp_RGB:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
				}
				return;
			}
		case ePVRTPF_PVRTCI_4bpp_RGBA:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
				}
				return;
			}
#ifndef TARGET_OS_IPHONE
		case ePVRTPF_PVRTCII_2bpp:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG;
				}
				return;
			}
		case ePVRTPF_PVRTCII_4bpp:
			{
				if (ColourSpace == ePVRTCSpacesRGB)
				{
					//glInternalFormat=GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;
				}
				return;
			}
		case ePVRTPF_ETC1:
			{
				glInternalFormat=GL_ETC1_RGB8_OES;
				return;
			}
#endif
		case ePVRTPF_ETC2_RGB:
			{
				if (ColourSpace==ePVRTCSpacesRGB)
					glInternalFormat=GL_COMPRESSED_SRGB8_ETC2;
				else
					glInternalFormat=GL_COMPRESSED_RGB8_ETC2;
				return;
			}
		case ePVRTPF_ETC2_RGBA:
			{
				if (ColourSpace==ePVRTCSpacesRGB)
					glInternalFormat=GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
				else
					glInternalFormat=GL_COMPRESSED_RGBA8_ETC2_EAC;
				return;
			}
		case ePVRTPF_ETC2_RGB_A1:
			{
				if (ColourSpace==ePVRTCSpacesRGB)
					glInternalFormat=GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
				else
					glInternalFormat=GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
				return;
			}
		case ePVRTPF_EAC_R11:
			{
				if (ChannelType==ePVRTVarTypeSignedInteger || ChannelType==ePVRTVarTypeSignedIntegerNorm || 
					ChannelType==ePVRTVarTypeSignedShort || ChannelType==ePVRTVarTypeSignedShortNorm || 
					ChannelType==ePVRTVarTypeSignedByte || ChannelType==ePVRTVarTypeSignedByteNorm || 
					ChannelType==ePVRTVarTypeSignedFloat)
				{
					glInternalFormat=GL_COMPRESSED_SIGNED_R11_EAC;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_R11_EAC;
				}
				return;
			}
		case ePVRTPF_EAC_RG11:
			{
				if (ChannelType==ePVRTVarTypeSignedInteger || ChannelType==ePVRTVarTypeSignedIntegerNorm || 
					ChannelType==ePVRTVarTypeSignedShort || ChannelType==ePVRTVarTypeSignedShortNorm || 
					ChannelType==ePVRTVarTypeSignedByte || ChannelType==ePVRTVarTypeSignedByteNorm || 
					ChannelType==ePVRTVarTypeSignedFloat)
				{
					glInternalFormat=GL_COMPRESSED_SIGNED_RG11_EAC;
				}
				else
				{
					glInternalFormat=GL_COMPRESSED_RG11_EAC;
				}
				return;
			}
		}
	}
	else
	{
		switch (ChannelType)
		{
		case ePVRTVarTypeUnsignedFloat:
			if (PixelFormat==PVRTGENPIXELID3('r','g','b',11,11,10) )
			{
				glType=GL_UNSIGNED_INT_10F_11F_11F_REV;
				glFormat = GL_RGB;
				glInternalFormat=GL_R11F_G11F_B10F;
				return;
			}
			break;
		case ePVRTVarTypeSignedFloat:
			{
				switch (PixelFormat)
				{
					//HALF_FLOAT
				case PVRTGENPIXELID4('r','g','b','a',16,16,16,16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_RGBA;
						glInternalFormat=GL_RGBA;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',16,16,16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_RGB;
						glInternalFormat=GL_RGB16F;
						return;
					}
				case PVRTGENPIXELID2('r','g',16,16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_RG;
						glInternalFormat=GL_RG16F;
						return;
					}
				case PVRTGENPIXELID1('r',16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_RED;
						glInternalFormat=GL_R16F;
						return;
					}
				case PVRTGENPIXELID2('l','a',16,16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_LUMINANCE_ALPHA;
						glInternalFormat=GL_LUMINANCE_ALPHA;
						return;
					}
				case PVRTGENPIXELID1('l',16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_LUMINANCE;
						glInternalFormat=GL_LUMINANCE;
						return;
					}
				case PVRTGENPIXELID1('a',16):
					{
						glType=GL_HALF_FLOAT;
						glFormat = GL_ALPHA;
						glInternalFormat=GL_ALPHA;
						return;
					}
					//FLOAT
				case PVRTGENPIXELID4('r','g','b','a',32,32,32,32):
					{
						glType=GL_FLOAT;
						glFormat = GL_RGBA;
						glInternalFormat=GL_RGBA32F;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',32,32,32):
					{
						glType=GL_FLOAT;
						glFormat = GL_RGB;
						glInternalFormat=GL_RGB32F;
						return;
					}
				case PVRTGENPIXELID2('r','g',32,32):
					{
						glType=GL_FLOAT;
						glFormat = GL_RG;
						glInternalFormat=GL_RG32F;
						return;
					}
				case PVRTGENPIXELID1('r',32):
					{
						glType=GL_FLOAT;
						glFormat = GL_RED;
						glInternalFormat=GL_R32F;
						return;
					}
				case PVRTGENPIXELID2('l','a',32,32):
					{
						glType=GL_FLOAT;
						glFormat = GL_LUMINANCE_ALPHA;
						glInternalFormat=GL_LUMINANCE_ALPHA;
						return;
					}
				case PVRTGENPIXELID1('l',32):
					{
						glType=GL_FLOAT;
						glFormat = GL_LUMINANCE;
						glInternalFormat=GL_LUMINANCE;
						return;
					}
				case PVRTGENPIXELID1('a',32):
					{
						glType=GL_FLOAT;
						glFormat = GL_ALPHA;
						glInternalFormat=GL_ALPHA;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeUnsignedByteNorm:
			{
				glType = GL_UNSIGNED_BYTE;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',8,8,8,8):
					{
						glFormat = GL_RGBA;
						if (ColourSpace==ePVRTCSpacesRGB)
							glInternalFormat=GL_SRGB8_ALPHA8;
						else
							glInternalFormat=GL_RGBA8;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',8,8,8):
					{
						glFormat = GL_RGB;
						if (ColourSpace==ePVRTCSpacesRGB)
							glInternalFormat=GL_SRGB8;
						else
							glInternalFormat=GL_RGB8;
						return;
					}
				case PVRTGENPIXELID2('r','g',8,8):
					{
						glFormat = GL_RG;
						glInternalFormat=GL_RG8;
						return;
					}
				case PVRTGENPIXELID1('r',8):
					{
						glFormat = GL_RED;
						glInternalFormat=GL_R8;
						return;
					}
				case PVRTGENPIXELID2('l','a',8,8):
					{
						glFormat = GL_LUMINANCE_ALPHA;
						glInternalFormat=GL_LUMINANCE_ALPHA;
						return;
					}
				case PVRTGENPIXELID1('l',8):
					{
						glFormat = GL_LUMINANCE;
						glInternalFormat=GL_LUMINANCE;
						return;
					}
				case PVRTGENPIXELID1('a',8):
					{
						glFormat = GL_ALPHA;
						glInternalFormat=GL_ALPHA;
						return;
					}
				case PVRTGENPIXELID4('b','g','r','a',8,8,8,8):
					{
						glFormat = GL_BGRA_EXT;
						glInternalFormat=GL_BGRA_EXT;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeSignedByteNorm:
			{
				glType = GL_BYTE;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',8,8,8,8):
					{
						glFormat = GL_RGBA;
						glInternalFormat=GL_RGBA8_SNORM;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',8,8,8):
					{
						glFormat = GL_RGB;
						glInternalFormat=GL_RGB8_SNORM;
						return;
					}
				case PVRTGENPIXELID2('r','g',8,8):
					{
						glFormat = GL_RG;
						glInternalFormat=GL_RGB8_SNORM;
						return;
					}
				case PVRTGENPIXELID1('r',8):
					{
						glFormat = GL_RED;
						glInternalFormat=GL_R8_SNORM;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeUnsignedByte:
			{
				glType = GL_UNSIGNED_BYTE;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',8,8,8,8):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA8UI;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',8,8,8):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB8UI;
						return;
					}
				case PVRTGENPIXELID2('r','g',8,8):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG8UI;
						return;
					}
				case PVRTGENPIXELID1('r',8):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R8UI;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeSignedByte:
			{
				glType = GL_BYTE;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',8,8,8,8):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA8I;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',8,8,8):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB8I;
						return;
					}
				case PVRTGENPIXELID2('r','g',8,8):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG8I;
						return;
					}
				case PVRTGENPIXELID1('r',8):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R8I;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeUnsignedShortNorm:
			{
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',4,4,4,4):
					{
						glType = GL_UNSIGNED_SHORT_4_4_4_4;
						glFormat = GL_RGBA;
						glInternalFormat=GL_RGBA4;
						return;
					}
				case PVRTGENPIXELID4('r','g','b','a',5,5,5,1):
					{
						glType = GL_UNSIGNED_SHORT_5_5_5_1;
						glFormat = GL_RGBA;
						glInternalFormat=GL_RGB5_A1;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',5,6,5):
					{
						glType = GL_UNSIGNED_SHORT_5_6_5;
						glFormat = GL_RGB;
						glInternalFormat=GL_RGB565;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeUnsignedShort:
			{
				glType = GL_UNSIGNED_SHORT;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',16,16,16,16):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA16UI;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',16,16,16):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB16UI;
						return;
					}
				case PVRTGENPIXELID2('r','g',16,16):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG16UI;
						return;
					}
				case PVRTGENPIXELID1('r',16):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R16UI;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeSignedShort:
			{
				glType = GL_SHORT;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',16,16,16,16):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA16I;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',16,16,16):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB16I;
						return;
					}
				case PVRTGENPIXELID2('r','g',16,16):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG16I;
						return;
					}
				case PVRTGENPIXELID1('r',16):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R16I;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeUnsignedIntegerNorm:
			{
				if (PixelFormat==PVRTGENPIXELID4('a','b','g','r',2,10,10,10))
				{
					glType = GL_UNSIGNED_INT_2_10_10_10_REV;
					glFormat = GL_RGBA;
					glInternalFormat=GL_RGB10_A2;
					return;
				}
				break;
			}
		case ePVRTVarTypeUnsignedInteger:
			{
				glType = GL_UNSIGNED_INT;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',32,32,32,32):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA32UI;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',32,32,32):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB32UI;
						return;
					}
				case PVRTGENPIXELID2('r','g',32,32):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG32UI;
						return;
					}
				case PVRTGENPIXELID1('r',32):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R32UI;
						return;
					}
				case PVRTGENPIXELID4('a','b','g','r',2,10,10,10):
					{
						glType = GL_UNSIGNED_INT_2_10_10_10_REV;
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGB10_A2UI;
						return;
					}
				}
				break;
			}
		case ePVRTVarTypeSignedInteger:
			{
				glType = GL_INT;
				switch (PixelFormat)
				{
				case PVRTGENPIXELID4('r','g','b','a',32,32,32,32):
					{
						glFormat = GL_RGBA_INTEGER;
						glInternalFormat=GL_RGBA32I;
						return;
					}
				case PVRTGENPIXELID3('r','g','b',32,32,32):
					{
						glFormat = GL_RGB_INTEGER;
						glInternalFormat=GL_RGB32I;
						return;
					}
				case PVRTGENPIXELID2('r','g',32,32):
					{
						glFormat = GL_RG_INTEGER;
						glInternalFormat=GL_RG32I;
						return;
					}
				case PVRTGENPIXELID1('r',32):
					{
						glFormat = GL_RED_INTEGER;
						glInternalFormat=GL_R32I;
						return;
					}
				}
				break;
			}
		default: { }
		}
	}

	//Default (erroneous) return values.
	glType = glFormat = glInternalFormat = 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;
				}
			}
		}
/*!***********************************************************************
	@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 PVRTGetOGLESTextureFormat(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;
			}
		default:
			return;
		}
	}
	else
	{
		switch (ChannelType)
		{
		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;
					}
				default:
					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;
					}
				default:
					return;
				}
				break;
			}
		default:
			return;
		}
	}
}