Implemented support for RLE compressed TGA images

Image import pipeline can now generate pre-multiplied alpha output images while they are compressed.

--HG--
branch : nfb
This commit is contained in:
2014-01-23 21:40:29 -08:00
parent c5da1dd7e1
commit 2ec9d5cf76
11 changed files with 150 additions and 16 deletions

View File

@@ -111,7 +111,7 @@ bool KRTexture::isAnimated()
return false;
}
KRTexture *KRTexture::compress()
KRTexture *KRTexture::compress(bool premultiply_alpha)
{
return NULL;
}

View File

@@ -59,7 +59,7 @@ public:
virtual void resetPoolExpiry();
virtual bool isAnimated();
virtual KRTexture *compress();
virtual KRTexture *compress(bool premultiply_alpha = false);
int getCurrentLodMaxDim();
int getMaxMipMap();
int getMinMipMap();

View File

@@ -46,7 +46,7 @@ public:
virtual bool save(const std::string& path);
virtual bool save(KRDataBlock &data);
virtual bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false) = 0;
virtual bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0;
virtual void bind(GLuint texture_unit);
protected:

View File

@@ -153,7 +153,7 @@ long KRTextureKTX::getMemRequiredForSize(int max_dim)
return memoryRequired;
}
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress)
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
{
int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim;

View File

@@ -19,7 +19,7 @@ public:
virtual ~KRTextureKTX();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim);

View File

@@ -393,14 +393,14 @@ unordered_map<std::string, KRTexture *> &KRTextureManager::getTextures()
return m_textures;
}
void KRTextureManager::compress()
void KRTextureManager::compress(bool premultiply_alpha)
{
std::vector<KRTexture *> textures_to_remove;
std::vector<KRTexture *> textures_to_add;
for(unordered_map<std::string, KRTexture *>::iterator itr=m_textures.begin(); itr != m_textures.end(); itr++) {
KRTexture *texture = (*itr).second;
KRTexture *compressed_texture = texture->compress();
KRTexture *compressed_texture = texture->compress(premultiply_alpha);
if(compressed_texture) {
textures_to_remove.push_back(texture);
textures_to_add.push_back(compressed_texture);

View File

@@ -66,7 +66,7 @@ public:
unordered_map<std::string, KRTexture *> &getTextures();
void compress();
void compress(bool premultiply_alpha = false);
std::set<KRTexture *> &getActiveTextures();
std::set<KRTexture *> &getPoolTextures();

View File

@@ -173,7 +173,7 @@ long KRTexturePVR::getMemRequiredForSize(int max_dim)
return memoryRequired;
}
bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress)
bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
{
int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim;

View File

@@ -18,7 +18,7 @@ public:
virtual ~KRTexturePVR();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim);

View File

@@ -36,6 +36,7 @@ KRTextureTGA::KRTextureTGA(KRContext &context, KRDataBlock *data, std::string na
m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images
switch(pHeader->imagetype) {
case 2: // rgb
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 24:
{
@@ -70,7 +71,7 @@ KRTextureTGA::~KRTextureTGA()
}
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress)
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
{
m_pData->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart();
@@ -133,7 +134,26 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
break;
case 32:
{
glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)pData);
if(premultiply_alpha) {
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = pData + pHeader->height * pHeader->width * 3;
while(pSource < pEnd) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image);
free(converted_image);
} else {
glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)pData);
}
err = glGetError();
if (err != GL_NO_ERROR) {
m_pData->unlock();
@@ -147,6 +167,120 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
return false; // 16-bit images not yet supported
}
break;
case 10: // rgb + rle
switch(pHeader->bitsperpixel) {
case 24:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
if(premultiply_alpha) {
while(pDest < pEnd) {
int count = *pSource & 0x7f + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = (__uint32_t)pSource[0] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[1] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = (__uint32_t)pSource[2] * (__uint32_t)pSource[3] / 0xff;
*pDest++ = pSource[3];
pSource += 4;
}
}
}
} else {
while(pDest < pEnd) {
int count = *pSource & 0x7f + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
}
pSource += 4;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = pSource[3];
pSource += 4;
}
}
}
}
glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image);
free(converted_image);
err = glGetError();
if (err != GL_NO_ERROR) {
m_pData->unlock();
return false;
}
current_lod_max_dim = m_max_lod_max_dim;
}
break;
case 32:
{
unsigned char *converted_image = (unsigned char *)malloc(pHeader->width * pHeader->height * 4);
unsigned char *pSource = pData;
unsigned char *pDest = converted_image;
unsigned char *pEnd = converted_image + pHeader->height * pHeader->width * 4;
while(pDest < pEnd) {
int count = *pSource & 0x7f + 1;
if(*pSource & 0x80) {
// RLE Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
}
pSource += 3;
} else {
// RAW Packet
pSource++;
while(count--) {
*pDest++ = pSource[0];
*pDest++ = pSource[1];
*pDest++ = pSource[2];
*pDest++ = 0xff;
pSource += 3;
}
}
}
glTexImage2D(target, 0, internal_format, pHeader->width, pHeader->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid *)converted_image);
free(converted_image);
err = glGetError();
if (err != GL_NO_ERROR) {
m_pData->unlock();
return false;
}
current_lod_max_dim = m_max_lod_max_dim;
}
break;
default:
m_pData->unlock();
return false; // 16-bit images not yet supported
}
break;
default:
m_pData->unlock();
return false; // Image type not yet supported
@@ -156,7 +290,7 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
return true;
}
KRTexture *KRTextureTGA::compress()
KRTexture *KRTextureTGA::compress(bool premultiply_alpha)
{
m_pData->lock();
@@ -170,7 +304,7 @@ KRTexture *KRTextureTGA::compress()
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle));
int current_max_dim = 0;
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, 0, true)) {
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, 0, true, premultiply_alpha)) {
assert(false); // Failed to upload the texture
}
GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D));

View File

@@ -18,8 +18,8 @@ public:
virtual ~KRTextureTGA();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false);
virtual KRTexture *compress();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
virtual KRTexture *compress(bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim);
private: