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; return false;
} }
KRTexture *KRTexture::compress() KRTexture *KRTexture::compress(bool premultiply_alpha)
{ {
return NULL; return NULL;
} }

View File

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

View File

@@ -46,7 +46,7 @@ public:
virtual bool save(const std::string& path); virtual bool save(const std::string& path);
virtual bool save(KRDataBlock &data); 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); virtual void bind(GLuint texture_unit);
protected: protected:

View File

@@ -153,7 +153,7 @@ long KRTextureKTX::getMemRequiredForSize(int max_dim)
return memoryRequired; 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; int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_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 ~KRTextureKTX();
virtual std::string getExtension(); 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); virtual long getMemRequiredForSize(int max_dim);

View File

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

View File

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

View File

@@ -173,7 +173,7 @@ long KRTexturePVR::getMemRequiredForSize(int max_dim)
return memoryRequired; 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; int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_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 ~KRTexturePVR();
virtual std::string getExtension(); 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); 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 m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images
switch(pHeader->imagetype) { switch(pHeader->imagetype) {
case 2: // rgb case 2: // rgb
case 10: // rgb + rle
switch(pHeader->bitsperpixel) { switch(pHeader->bitsperpixel) {
case 24: 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(); m_pData->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart(); 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; break;
case 32: 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(); err = glGetError();
if (err != GL_NO_ERROR) { if (err != GL_NO_ERROR) {
m_pData->unlock(); 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 return false; // 16-bit images not yet supported
} }
break; 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: default:
m_pData->unlock(); m_pData->unlock();
return false; // Image type not yet supported 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; return true;
} }
KRTexture *KRTextureTGA::compress() KRTexture *KRTextureTGA::compress(bool premultiply_alpha)
{ {
m_pData->lock(); m_pData->lock();
@@ -170,7 +304,7 @@ KRTexture *KRTextureTGA::compress()
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle)); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle));
int current_max_dim = 0; 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 assert(false); // Failed to upload the texture
} }
GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D)); GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D));

View File

@@ -18,8 +18,8 @@ public:
virtual ~KRTextureTGA(); virtual ~KRTextureTGA();
virtual std::string getExtension(); 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 KRTexture *compress(); virtual KRTexture *compress(bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim); virtual long getMemRequiredForSize(int max_dim);
private: private: