mirror of
https://github.com/love2d/love.git
synced 2026-08-15 15:51:12 +02:00
Added support for ETC1 and PVR1 compressed textures contained in KTX, PKM, and PVR files.
Most desktop graphics drivers don't support those formats. --HG-- branch : minor
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2014 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
// LOVE
|
||||
#include "PKMHandler.h"
|
||||
#include "common/int.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace image
|
||||
{
|
||||
namespace magpie
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Big endian to host (and vice versa.)
|
||||
inline uint16 swap16big(uint16 x)
|
||||
{
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
return x;
|
||||
#else
|
||||
return swap16(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const uint8 pkmIdentifier[] = {'P','K','M',' '};
|
||||
|
||||
struct PKMHeader
|
||||
{
|
||||
uint8 identifier[4];
|
||||
uint8 version[2];
|
||||
uint16 textureFormatBig;
|
||||
uint16 extendedWidthBig;
|
||||
uint16 extendedHeightBig;
|
||||
uint16 widthBig;
|
||||
uint16 heightBig;
|
||||
};
|
||||
|
||||
enum PKMTextureFormat
|
||||
{
|
||||
ETC1_RGB_NO_MIPMAPS = 0,
|
||||
ETC2PACKAGE_RGB_NO_MIPMAPS,
|
||||
ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD,
|
||||
ETC2PACKAGE_RGBA_NO_MIPMAPS,
|
||||
ETC2PACKAGE_RGBA1_NO_MIPMAPS,
|
||||
ETC2PACKAGE_R_NO_MIPMAPS,
|
||||
ETC2PACKAGE_RG_NO_MIPMAPS,
|
||||
ETC2PACKAGE_R_SIGNED_NO_MIPMAPS,
|
||||
ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS
|
||||
};
|
||||
|
||||
CompressedData::Format convertFormat(uint16 texformat)
|
||||
{
|
||||
switch (texformat)
|
||||
{
|
||||
case ETC1_RGB_NO_MIPMAPS:
|
||||
return CompressedData::FORMAT_ETC1;
|
||||
default:
|
||||
return CompressedData::FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
} // Anonymous namespace.
|
||||
|
||||
bool PKMHandler::canParse(const filesystem::FileData *data)
|
||||
{
|
||||
if (data->getSize() <= sizeof(PKMHeader))
|
||||
return false;
|
||||
|
||||
const PKMHeader *header = (const PKMHeader *) data->getData();
|
||||
|
||||
if (memcmp(header->identifier, pkmIdentifier, 4) != 0)
|
||||
return false;
|
||||
|
||||
// At the time of this writing, only v1.0 and v2.0 exist.
|
||||
if ((header->version[0] != '2' && header->version[0] != '1') || header->version[1] != '0')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 *PKMHandler::parse(filesystem::FileData *filedata, std::vector<CompressedData::SubImage> &images, size_t &dataSize, CompressedData::Format &format)
|
||||
{
|
||||
if (!canParse(filedata))
|
||||
throw love::Exception("Could not decode compressed data (not a PKM file?)");
|
||||
|
||||
PKMHeader header = *(const PKMHeader *) filedata->getData();
|
||||
|
||||
header.textureFormatBig = swap16big(header.textureFormatBig);
|
||||
header.extendedWidthBig = swap16big(header.extendedWidthBig);
|
||||
header.extendedHeightBig = swap16big(header.extendedHeightBig);
|
||||
header.widthBig = swap16big(header.widthBig);
|
||||
header.heightBig = swap16big(header.heightBig);
|
||||
|
||||
CompressedData::Format cformat = convertFormat(header.textureFormatBig);
|
||||
|
||||
if (cformat == CompressedData::FORMAT_UNKNOWN)
|
||||
throw love::Exception("Could not parse PKM file: unsupported texture format.");
|
||||
|
||||
// The rest of the file after the header is all texture data.
|
||||
size_t totalsize = filedata->getSize() - sizeof(PKMHeader);
|
||||
uint8 *data = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
data = new uint8[totalsize];
|
||||
}
|
||||
catch (std::bad_alloc &)
|
||||
{
|
||||
throw love::Exception("Out of memory.");
|
||||
}
|
||||
|
||||
// PKM files only store a single mipmap level.
|
||||
memcpy(data, (uint8 *) filedata->getData() + sizeof(PKMHeader), totalsize);
|
||||
|
||||
CompressedData::SubImage mip;
|
||||
|
||||
// TODO: verify whether glCompressedTexImage works properly with the unpadded
|
||||
// width and height values (extended == padded.)
|
||||
mip.width = header.widthBig;
|
||||
mip.height = header.heightBig;
|
||||
|
||||
mip.size = totalsize;
|
||||
mip.data = data;
|
||||
|
||||
images.push_back(mip);
|
||||
|
||||
dataSize = totalsize;
|
||||
format = cformat;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // magpie
|
||||
} // image
|
||||
} // love
|
||||
|
||||
Reference in New Issue
Block a user