1、ETC1图片是android下通用的压缩纹理,几乎所有的android机器都支持,是opengles2.0的标准。不像pvrtc4只是部分powervr的显卡支持。
ETC1图片不支持半透明(有替代方案可以使etc1图片兼容半透明显示),内存占用只有正常RGBA8888的八分之一(一个像素0.5个字节),并且具备极高的加载速度。ETC1的图片大小只跟图片尺寸相关,在大小上无法媲美jpg或者png8的图片。
2、cocos2d-x早期使用android提供的ETC1Util来加载纹理,后面经过一次优化,改变成直接读取文件的加载方式。 也就是说ETC1文件前面16个字节是文件头,包含文件宽高等信息。 除开这16个字节,剩下的就是图片像素数据,这些数据可以直接传递给显卡使用glCompressedTexImage2D来创建纹理。
3、同样在这次优化中,加入了软件解压ETC1的功能,这样windows等桌面平台也可以使用ETC1的图片了(虽然没有任何优势可言)。但是实现有一些bug,导致不兼容非2的整次幂的图片。修改如下
//if it is not gles or device do not support ETC, decode texture by software
int bytePerPixel = 3;
GLenum fallBackType = GL_UNSIGNED_BYTE;
/*bool fallBackUseShort = false;
if(fallBackUseShort)
{
bytePerPixel = 2;
fallBackType = GL_UNSIGNED_SHORT_5_6_5;
}
*/
unsigned int stride = _width * bytePerPixel;
std::vector<unsigned char> decodeImageData(((stride + 3) &~ 3) * ((_height + 3) &~3));
etc1_decode_image(etcFileData + ETC_PKM_HEADER_SIZE, &decodeImageData[0], _width, _height, bytePerPixel, ((stride + 3) &~ 3));
//set decoded data to gl
glGenTextures(1, &_name);
glBindTexture(GL_TEXTURE_2D, _name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, fallBackType, &decodeImageData[0]);
glBindTexture(GL_TEXTURE_2D, 0);
delete[] etcFileData;
etcFileData = NULL;
return true;
注意其中两句
std::vector<unsigned char> decodeImageData(((stride + 3) &~ 3) * ((_height + 3) &~3));
etc1_decode_image(etcFileData + ETC_PKM_HEADER_SIZE, &decodeImageData[0], _width, _height, bytePerPixel, ((stride + 3) &~ 3));
分配内存必须能够容纳下图片数据,而ETC1图片会进行4字节对齐(圆整),所以宽高不能直接使用原始图片数据。 当然,不修改的话对于2的整次幂的图片也是没有问题的,因为本身就是对齐的,不需要圆整了。
4、android下部分机器兼容非2的整次幂的etc1图片,但是同样也有部分机器不兼容。遇到非2的整次幂的图片会渲染错误甚至崩溃。所以android下使用etc1图片需要进行2的整次幂的扩展。如果大量零碎文件的话,考虑使用TexturePacker打包图片