//----------------------------------------------------------------------------//
Texture* PVRImageCodec::load(const RawDataContainer& data, Texture* result)
{
    const PVR_Texture_Header* pvr_header =
        reinterpret_cast<const PVR_Texture_Header*>(data.getDataPtr());

    // convert header to big endian if required
    PVR_Texture_Header converted_pvr_header;
    if (!PVRTIsLittleEndian())
    {
        converted_pvr_header = *pvr_header;

        PVRTuint32* data = reinterpret_cast<PVRTuint32*>(&converted_pvr_header);
        for (uint i = 0; i < sizeof(PVR_Texture_Header) / sizeof(PVRTuint32); i++)
            PVRTByteSwap(reinterpret_cast<PVRTuint8*>(data++), sizeof(PVRTuint32));

        pvr_header = &converted_pvr_header;
    }

    // perform checks for old PVR psPVRHeader
    if (pvr_header->dwHeaderSize != sizeof(PVR_Texture_Header))
    {
        // Unknow or old format
        Logger::getSingletonPtr()->logEvent(
            "PVRImageCodec::load - unknown or old texture format.  "
            "Use PVRTexTool to save in appropriate format.", Errors);
        return 0;
    }

    if (pvr_header->dwpfFlags & PVRTEX_CUBEMAP)
    {
        //Cube maps are not supported
        Logger::getSingletonPtr()->logEvent(
            "PVRImageCodec::load - cubemap textures unsupported.", Errors);
        return 0;
    }

    /* Only accept untwiddled data UNLESS texture format is PVRTC */
    if (((pvr_header->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) &&
        ((pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC2) &&
        ((pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC4))
    {
        // We need to load untwiddled textures -- hw will twiddle for us.
        Logger::getSingletonPtr()->logEvent(
            "PVRImageCodec::load - Texture should be untwiddled", Errors);
        return 0;
    }

    CEGUI::Texture::PixelFormat cefmt;
    bool is_compressed_format = false;

    switch (pvr_header->dwpfFlags & PVRTEX_PIXELTYPE)
    {
    case OGL_RGBA_4444:
        cefmt = CEGUI::Texture::PF_RGBA_4444;
        break;

    case OGL_RGBA_5551:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "pixel format RGBA_5551 not supported.", Errors);
        return 0;

    case OGL_RGB_565:
        cefmt = CEGUI::Texture::PF_RGB_565;
        break;

    case OGL_RGB_555:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "pixel format RGB_555 not supported.", Errors);
        return 0;

    case OGL_I_8:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "pixel format I_8 not supported.", Errors);
        return 0;

    case OGL_AI_88:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "pixel format AI_88 not supported.", Errors);
        return 0;

    case OGL_BGRA_8888:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "pixel format BGRA8888 not supported.", Errors);
        return 0;

    case OGL_RGBA_8888:
        cefmt = CEGUI::Texture::PF_RGBA;
        break;

    case OGL_RGB_888:
        cefmt = CEGUI::Texture::PF_RGB;
        break;

    case MGLPT_PVRTC2:
    case OGL_PVRTC2:
        cefmt = CEGUI::Texture::PF_PVRTC2;
        is_compressed_format = true;
        break;

    case MGLPT_PVRTC4:
    case OGL_PVRTC4:
        cefmt = CEGUI::Texture::PF_PVRTC4;
        is_compressed_format = true;
        break;

    default:
        Logger::getSingletonPtr()->logEvent("PVRImageCodec::load - "
            "wrong pvr pixel format.", Errors);
        return 0;
    }

    const void* texture_data =
        reinterpret_cast<const void*>(data.getDataPtr() + pvr_header->dwHeaderSize);
    const uint size_x = pvr_header->dwWidth;
    const uint size_y = pvr_header->dwHeight;

    if (is_compressed_format)
    {
        if (result->isPixelFormatSupported(cefmt))
        {
            result->loadFromMemory(texture_data,
                                   Sizef(static_cast<float>(size_x),
                                         static_cast<float>(size_y)),
                                   cefmt);
        }
        else
        {
            // Convert PVRTC to 32-bit RGBA
            PVRTuint8* decompressed_texture = new PVRTuint8[size_x * size_y * 4];

            int bit_mode = (pvr_header->dwpfFlags & PVRTEX_PIXELTYPE) == OGL_PVRTC2;
            PVRTDecompressPVRTC(texture_data, bit_mode, size_x, size_y,
                                decompressed_texture);

            cefmt = CEGUI::Texture::PF_RGBA; // Redefine to uncompressed format
            result->loadFromMemory(decompressed_texture,
                                   Sizef(static_cast<float>(size_x),
                                         static_cast<float>(size_y)),
                                   cefmt);
            delete[] decompressed_texture;
        }
    }
    else
    {
        // Perform raw data load from textureData
        result->loadFromMemory(texture_data,
                               Sizef(static_cast<float>(size_x),
                                     static_cast<float>(size_y)),
                               cefmt);
    }


    return result;
}
static void WriteHScene(
	FILE			* const pFile,
	const SPODScene	&s,
	const char		* const sName)
{
	char sCamera[CFAH] = "0";
	char sLight[CFAH] = "0";
	char sMesh[CFAH] = "0";
	char sNode[CFAH] = "0";
	char sTexture[CFAH] = "0";
	char sMaterial[CFAH] = "0";

	bool bChangeEndian = s.bBigEndian == PVRTIsLittleEndian();

	if(s.nNumCamera)
	{
		sprintf(sCamera, "%sCamera", sName);
		WriteHCameras(pFile, s, sCamera, bChangeEndian);
	}

	if(s.nNumLight)
	{
		sprintf(sLight, "%sLight", sName);
		WriteHLights(pFile, s, sLight);
	}

	if(s.nNumMesh)
	{
		sprintf(sMesh, "%sMesh", sName);
		WriteHMeshes(pFile, s, sMesh, bChangeEndian);
	}

	if(s.nNumNode)
	{
		sprintf(sNode, "%sNode", sName);
		WriteHNodes(pFile, s, sNode, bChangeEndian);
	}

	if(s.nNumTexture)
	{
		sprintf(sTexture, "%sTexture", sName);
		WriteHTextures(pFile, s, sTexture, bChangeEndian);
	}

	if(s.nNumMaterial)
	{
		sprintf(sMaterial, "%sMaterial", sName);
		WriteHMaterials(pFile, s, sMaterial, bChangeEndian);
	}

	fprintf(pFile, "const SPODScene %s =\n", sName);
	fprintf(pFile, "{\n");
	if(s.nFlags & PVRTMODELPODSF_FIXED)
	{
		fprintf(pFile, "	{ 0x%08x, 0x%08x, 0x%08x },\n", (int&)s.pfColourBackground[0], (int&)s.pfColourBackground[1], (int&)s.pfColourBackground[2]);
		fprintf(pFile, "	{ 0x%08x, 0x%08x, 0x%08x },\n", (int&)s.pfColourAmbient[0], (int&)s.pfColourAmbient[1], (int&)s.pfColourAmbient[2]);
	}
	else
	{
		fprintf(pFile, "	{ %ff, %ff, %ff },\n", s.pfColourBackground[0], s.pfColourBackground[1], s.pfColourBackground[2]);
		fprintf(pFile, "	{ %ff, %ff, %ff },\n", s.pfColourAmbient[0], s.pfColourAmbient[1], s.pfColourAmbient[2]);
	}
	fprintf(pFile, "	%d,\n", s.nNumCamera);
	fprintf(pFile, "	(SPODCamera*)%s,\n", sCamera);
	fprintf(pFile, "	%d,\n", s.nNumLight);
	fprintf(pFile, "	(SPODLight*)%s,\n", sLight);
	fprintf(pFile, "	%d,\n", s.nNumMesh);
	fprintf(pFile, "	(SPODMesh*)%s,\n", sMesh);
	fprintf(pFile, "	%d,\n", s.nNumNode);
	fprintf(pFile, "	%d,\n", s.nNumMeshNode);
	fprintf(pFile, "	(SPODNode*)%s,\n", sNode);
	fprintf(pFile, "	%d,\n", s.nNumTexture);
	fprintf(pFile, "	(SPODTexture*)%s,\n", sTexture);
	fprintf(pFile, "	%d,\n", s.nNumMaterial);
	fprintf(pFile, "	(SPODMaterial*)%s,\n", sMaterial);
	fprintf(pFile, "	%d,\n", s.nNumFrame);
	fprintf(pFile, "	0x%08x,\n", s.nFlags);
	fprintf(pFile, "};\n");
	fprintf(pFile, "\n");
}