From 2ec9d5cf767fd58bb7fa2de99dbf9d363c0390e4 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Thu, 23 Jan 2014 21:40:29 -0800 Subject: [PATCH] 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 --- KREngine/kraken/KRTexture.cpp | 2 +- KREngine/kraken/KRTexture.h | 2 +- KREngine/kraken/KRTexture2D.h | 2 +- KREngine/kraken/KRTextureKTX.cpp | 2 +- KREngine/kraken/KRTextureKTX.h | 2 +- KREngine/kraken/KRTextureManager.cpp | 4 +- KREngine/kraken/KRTextureManager.h | 2 +- KREngine/kraken/KRTexturePVR.cpp | 2 +- KREngine/kraken/KRTexturePVR.h | 2 +- KREngine/kraken/KRTextureTGA.cpp | 142 ++++++++++++++++++++++++++- KREngine/kraken/KRTextureTGA.h | 4 +- 11 files changed, 150 insertions(+), 16 deletions(-) diff --git a/KREngine/kraken/KRTexture.cpp b/KREngine/kraken/KRTexture.cpp index 0f64489..ba640e5 100644 --- a/KREngine/kraken/KRTexture.cpp +++ b/KREngine/kraken/KRTexture.cpp @@ -111,7 +111,7 @@ bool KRTexture::isAnimated() return false; } -KRTexture *KRTexture::compress() +KRTexture *KRTexture::compress(bool premultiply_alpha) { return NULL; } diff --git a/KREngine/kraken/KRTexture.h b/KREngine/kraken/KRTexture.h index defc431..dccdd72 100644 --- a/KREngine/kraken/KRTexture.h +++ b/KREngine/kraken/KRTexture.h @@ -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(); diff --git a/KREngine/kraken/KRTexture2D.h b/KREngine/kraken/KRTexture2D.h index f7f4303..921370b 100644 --- a/KREngine/kraken/KRTexture2D.h +++ b/KREngine/kraken/KRTexture2D.h @@ -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 ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false) = 0; + virtual bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0; virtual void bind(GLuint texture_unit); protected: diff --git a/KREngine/kraken/KRTextureKTX.cpp b/KREngine/kraken/KRTextureKTX.cpp index 0550554..863c624 100644 --- a/KREngine/kraken/KRTextureKTX.cpp +++ b/KREngine/kraken/KRTextureKTX.cpp @@ -153,7 +153,7 @@ long KRTextureKTX::getMemRequiredForSize(int max_dim) return memoryRequired; } -bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress) +bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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; diff --git a/KREngine/kraken/KRTextureKTX.h b/KREngine/kraken/KRTextureKTX.h index 13308b8..f9f5d30 100644 --- a/KREngine/kraken/KRTextureKTX.h +++ b/KREngine/kraken/KRTextureKTX.h @@ -19,7 +19,7 @@ public: virtual ~KRTextureKTX(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false); virtual long getMemRequiredForSize(int max_dim); diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index 0e02202..58cca0e 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -393,14 +393,14 @@ unordered_map &KRTextureManager::getTextures() return m_textures; } -void KRTextureManager::compress() +void KRTextureManager::compress(bool premultiply_alpha) { std::vector textures_to_remove; std::vector textures_to_add; for(unordered_map::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); diff --git a/KREngine/kraken/KRTextureManager.h b/KREngine/kraken/KRTextureManager.h index cdf8b99..41b4b21 100644 --- a/KREngine/kraken/KRTextureManager.h +++ b/KREngine/kraken/KRTextureManager.h @@ -66,7 +66,7 @@ public: unordered_map &getTextures(); - void compress(); + void compress(bool premultiply_alpha = false); std::set &getActiveTextures(); std::set &getPoolTextures(); diff --git a/KREngine/kraken/KRTexturePVR.cpp b/KREngine/kraken/KRTexturePVR.cpp index 419ccbe..46f3ef4 100644 --- a/KREngine/kraken/KRTexturePVR.cpp +++ b/KREngine/kraken/KRTexturePVR.cpp @@ -173,7 +173,7 @@ long KRTexturePVR::getMemRequiredForSize(int max_dim) return memoryRequired; } -bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress) +bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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; diff --git a/KREngine/kraken/KRTexturePVR.h b/KREngine/kraken/KRTexturePVR.h index ea15878..3d973d4 100644 --- a/KREngine/kraken/KRTexturePVR.h +++ b/KREngine/kraken/KRTexturePVR.h @@ -18,7 +18,7 @@ public: virtual ~KRTexturePVR(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false); virtual long getMemRequiredForSize(int max_dim); diff --git a/KREngine/kraken/KRTextureTGA.cpp b/KREngine/kraken/KRTextureTGA.cpp index 257be52..c6b6a56 100644 --- a/KREngine/kraken/KRTextureTGA.cpp +++ b/KREngine/kraken/KRTextureTGA.cpp @@ -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 ¤t_lod_max_dim, int prev_lod_max_dim, bool compress) +bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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 ¤t_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 ¤t_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 ¤t_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)); diff --git a/KREngine/kraken/KRTextureTGA.h b/KREngine/kraken/KRTextureTGA.h index 34edb9d..ddea36d 100644 --- a/KREngine/kraken/KRTextureTGA.h +++ b/KREngine/kraken/KRTextureTGA.h @@ -18,8 +18,8 @@ public: virtual ~KRTextureTGA(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false); - virtual KRTexture *compress(); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_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: