一、OpenGL 纹理基础

纹理基础。
cocos2dx中的Texture2D类是对GL 纹理的封装,以便对GL纹理进行管理。

二、纹理格式

Cocos 3.17支持的纹理像素格式:

  1. class CC_DLL Texture2D : public Ref
  2. {
  3. enum class PixelFormat {
  4. AUTO, // 自动检测格式,即采用引擎内部的固定转化规则,比如解析png格式图片文件时,会根据不同
  5. // 情况,将PNG图片转化成不同的像素格式,下面会讲。
  6. //**************普通纹理格式
  7. // 事实上,最终的纹理格式就是RGB(A)格式,因为显示器就是采用的RGBA标准。
  8. BGRA8888, // 32位真彩色,4个通道:red、green、blue、alpha,
  9. RGBA8888, // 每个通道占用8bits。占用内存大,运算速度慢。
  10. RGB888, // 24位纹理,相比于上面,缺少alpha通道,所以不支持透明度。
  11. RGB565, // 16位纹理,红色通道5位,绿色通道6位,蓝色通道5位,没有透明通道。
  12. // 它能尽最大努力提供一个高品质的16位纹理,前提是不需要透明度的支持。
  13. // 因为人眼对绿色更敏感一些,所以G位多了1bit,
  14. // 适用于游戏背景。
  15. A8, // 用作蒙版(mask)的8位纹理,用来做遮罩图。
  16. I8, // 8位强度/灰度纹理,用来做灰度图使用。
  17. AI88, // 用作蒙版(mask)的16位纹理,存储透明和灰度双功能的值
  18. RGBA4444, // 包含RGBA通道的16位纹理,适用于需要有不同的透明度精灵
  19. RGB5A1, // 包含 RGB通道(各5bit)和alpha通道(1bit)的 6位纹理,适用于无需支持透明度的精灵
  20. //**************压缩纹理格式
  21. PVRTC4, // 4-bit PVRTC-compressed texture
  22. PVRTC4A, // 4-bit PVRTC-compressed texture (has alpha channel)
  23. PVRTC2, // 2-bit PVRTC-compressed texture
  24. PVRTC2A, // 2-bit PVRTC-compressed texture (has alpha channel)
  25. ETC, // ETC-compressed texture
  26. S3TC_DXT1, // S3TC-compressed texture
  27. S3TC_DXT3, // S3TC-compressed texture
  28. S3TC_DXT5, // S3TC-compressed texture
  29. ATC_RGB, // ATITC-compressed texture
  30. ATC_EXPLICIT_ALPHA, // ATITC-compressed texture
  31. ATC_INTERPOLATED_ALPHA, // ATITC-compressed texture
  32. DEFAULT = AUTO, // 默认是自动检测格式。
  33. };
  34. ......
  35. }

对于每种格式的纹理,在用glTexImage2D创建纹理的时候都有固定的参数,因此cocos用了一个map来存储这些映射数据。

  1. class CC_DLL Texture2D : public Ref
  2. {
  3. // 保存一种纹理格式对应的glTexImage2D参数。
  4. struct PixelFormatInfo {
  5. PixelFormatInfo(GLenum anInternalFormat,
  6. GLenum aFormat,
  7. GLenum aType,
  8. int aBpp,
  9. bool aCompressed,
  10. bool anAlpha)
  11. : internalFormat(anInternalFormat)
  12. , format(aFormat)
  13. , type(aType)
  14. , bpp(aBpp)
  15. , compressed(aCompressed)
  16. , alpha(anAlpha)
  17. {}
  18. GLenum internalFormat; // glTexImage2D参数interalformat
  19. GLenum format; // glTexImage2D参数format
  20. GLenum type; // glTexImage2D参数type
  21. int bpp; // bits per pixel
  22. bool compressed; // 是不是压缩纹理格式,不然就要用glCompressedTexImage2D
  23. bool alpha; // 是否支持alpha
  24. };
  25. // 纹理格式 -> 纹理参数
  26. typedef std::map<Texture2D::PixelFormat, const PixelFormatInfo> PixelFormatInfoMap;
  27. }
  28. // ***********************************************************
  29. // ********** CCTexture2D.cpp
  30. // ***********************************************************
  31. namespace {
  32. // map的value_type
  33. typedef Texture2D::PixelFormatInfoMap::value_type PixelFormatInfoMapValue;
  34. // 用一个数组来保存当前设备支持的纹理格式及其对应参数。
  35. // 通过预编译+数组来动态初始化map来减少内存占用。
  36. static const PixelFormatInfoMapValue TexturePixelFormatInfoTablesValue[] =
  37. {
  38. // 普通纹理格式
  39. PixelFormatInfoMapValue(Texture2D::PixelFormat::BGRA8888, Texture2D::PixelFormatInfo(GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE, 32, false, true)),
  40. PixelFormatInfoMapValue(Texture2D::PixelFormat::RGBA8888, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, false, true)),
  41. PixelFormatInfoMapValue(Texture2D::PixelFormat::RGBA4444, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, false, true)),
  42. PixelFormatInfoMapValue(Texture2D::PixelFormat::RGB5A1, Texture2D::PixelFormatInfo(GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, false, true)),
  43. PixelFormatInfoMapValue(Texture2D::PixelFormat::RGB565, Texture2D::PixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, false, false)),
  44. PixelFormatInfoMapValue(Texture2D::PixelFormat::RGB888, Texture2D::PixelFormatInfo(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, 24, false, false)),
  45. PixelFormatInfoMapValue(Texture2D::PixelFormat::A8, Texture2D::PixelFormatInfo(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, false, false)),
  46. PixelFormatInfoMapValue(Texture2D::PixelFormat::I8, Texture2D::PixelFormatInfo(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, false, false)),
  47. PixelFormatInfoMapValue(Texture2D::PixelFormat::AI88, Texture2D::PixelFormatInfo(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, false, true)),
  48. // PVRTC压缩纹理格式
  49. #ifdef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
  50. PixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC2, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, false)),
  51. PixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC2A, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 2, true, true)),
  52. PixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC4, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
  53. PixelFormatInfoMapValue(Texture2D::PixelFormat::PVRTC4A, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, true)),
  54. #endif
  55. #ifdef GL_ETC1_RGB8_OES
  56. PixelFormatInfoMapValue(Texture2D::PixelFormat::ETC, Texture2D::PixelFormatInfo(GL_ETC1_RGB8_OES, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
  57. #endif
  58. #ifdef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
  59. PixelFormatInfoMapValue(Texture2D::PixelFormat::S3TC_DXT1, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
  60. #endif
  61. #ifdef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
  62. PixelFormatInfoMapValue(Texture2D::PixelFormat::S3TC_DXT3, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
  63. #endif
  64. #ifdef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
  65. PixelFormatInfoMapValue(Texture2D::PixelFormat::S3TC_DXT5, Texture2D::PixelFormatInfo(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
  66. #endif
  67. #ifdef GL_ATC_RGB_AMD
  68. PixelFormatInfoMapValue(Texture2D::PixelFormat::ATC_RGB, Texture2D::PixelFormatInfo(GL_ATC_RGB_AMD, 0xFFFFFFFF, 0xFFFFFFFF, 4, true, false)),
  69. #endif
  70. #ifdef GL_ATC_RGBA_EXPLICIT_ALPHA_AMD
  71. PixelFormatInfoMapValue(Texture2D::PixelFormat::ATC_EXPLICIT_ALPHA, Texture2D::PixelFormatInfo(GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
  72. #endif
  73. #ifdef GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD
  74. PixelFormatInfoMapValue(Texture2D::PixelFormat::ATC_INTERPOLATED_ALPHA, Texture2D::PixelFormatInfo(GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, 0xFFFFFFFF, 0xFFFFFFFF, 8, true, false)),
  75. #endif
  76. };
  77. }
  78. // std::map(start, end)初始化map
  79. const Texture2D::PixelFormatInfoMap Texture2D::_pixelFormatInfoTables(TexturePixelFormatInfoTablesValue,
  80. TexturePixelFormatInfoTablesValue + sizeof(TexturePixelFormatInfoTablesValue) / sizeof(TexturePixelFormatInfoTablesValue[0]));

cocos检测设备对压缩纹理格式的支持:

  1. void Configuration::gatherGPUInfo() {
  2. ......
  3. _supportsETC1 = checkForGLExtension("GL_OES_compressed_ETC1_RGB8_texture");
  4. _valueDict["gl.supports_ETC1"] = Value(_supportsETC1);
  5. _supportsS3TC = checkForGLExtension("GL_EXT_texture_compression_s3tc");
  6. _valueDict["gl.supports_S3TC"] = Value(_supportsS3TC);
  7. _supportsATITC = checkForGLExtension("GL_AMD_compressed_ATC_texture");
  8. _valueDict["gl.supports_ATITC"] = Value(_supportsATITC);
  9. _supportsPVRTC = checkForGLExtension("GL_IMG_texture_compression_pvrtc");
  10. _valueDict["gl.supports_PVRTC"] = Value(_supportsPVRTC);
  11. ......
  12. }
  13. bool Configuration::supportsATITC() const {
  14. return _supportsATITC;
  15. }
  16. bool Configuration::supportsETC() const {
  17. //GL_ETC1_RGB8_OES is not defined in old opengl version
  18. #ifdef GL_ETC1_RGB8_OES
  19. return _supportsETC1;
  20. #else
  21. return false;
  22. #endif
  23. }
  24. bool Configuration::supportsS3TC() const {
  25. #ifdef GL_EXT_texture_compression_s3tc
  26. return _supportsS3TC;
  27. #else
  28. return false;
  29. #endif
  30. }
  31. bool Configuration::supportsPVRTC() const {
  32. return _supportsPVRTC;
  33. }

三、操作纹理

  1. Texture2D* pTexture = new Texture2D();
  2. // 在显存中创建GL纹理。
  3. pTexture->initWithData(......);
  4. pTexture->initWidthImage(......); // 从image file初始化
  5. pTexture->initWithMipmaps(......); // 多级纹理
  6. pTexture->initWithString(......); // 字体纹理
  7. ......; // 使用Texture2D
  8. CC_SAFE_RELEASE(pTexture); // 触发析构,在析构中,删除显存中的GL纹理。

1、纹理数据

Texture2D纹理中保存的数据:

  1. class CC_DLL Texture2D : public Ref {
  2. ......
  3. Texture2D::PixelFormat _pixelFormat; // 纹理格式
  4. int _pixelsWide; // 像素宽度
  5. int _pixelsHigh; // 像素高度
  6. GLuint _name; // texture name/id,GL纹理对象的句柄
  7. GLfloat _maxS; // 纹理坐标的s坐标的最大值(相当于X坐标)
  8. GLfloat _maxT; // 同上理(相当于Y坐标)
  9. Size _contentSize; // 像素宽高
  10. bool _hasPremultipliedAlpha; // 是否开启alpha预乘
  11. bool _hasMipmaps; // 是否是多级纹理
  12. GLProgram* _shaderProgram; // drawAtPoint and drawInRect时使用的shader program
  13. // 上面已讲
  14. static const PixelFormatInfoMap _pixelFormatInfoTables;
  15. bool _antialiasEnabled; // 是否开启抗锯齿,其实就是采用GL_LINEAR线性采样
  16. NinePatchInfo* _ninePatchInfo; // 待完成
  17. bool _valid; // 貌似没鸟用。
  18. std::string _filePath; // 如果是从image file初始化,则保存该image file的路径
  19. Texture2D* _alphaTexture; // 为了让ETC1纹理支持透明
  20. ......
  21. }

2、初始化纹理

initWithMipmaps

  1. // 多级纹理初始化
  2. bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, // MipmapInfo其实就是一个数组,保存纹理数据
  3. int mipmapsNum, // 纹理级数,=1表示普通纹理,只有一张纹理。
  4. PixelFormat pixelFormat, // 纹理像素格式
  5. int pixelsWide, // 纹理像素宽高
  6. int pixelsHigh)
  7. {
  8. //the pixelFormat must be a certain value
  9. CCASSERT(pixelFormat != PixelFormat::NONE && pixelFormat != PixelFormat::AUTO, "the \"pixelFormat\" param must be a certain value!");
  10. CCASSERT(pixelsWide>0 && pixelsHigh>0, "Invalid size");
  11. if (mipmapsNum <= 0)
  12. {
  13. CCLOG("cocos2d: WARNING: mipmap number is less than 1");
  14. return false;
  15. }
  16. // 纹理格式pixelFormat对应的glTexImage2D函数参数
  17. auto formatItr = _pixelFormatInfoTables.find(pixelFormat);
  18. if(formatItr == _pixelFormatInfoTables.end())
  19. {
  20. CCLOG("cocos2d: WARNING: unsupported pixelformat: %lx", (unsigned long)pixelFormat );
  21. return false;
  22. }
  23. const PixelFormatInfo& info = formatItr->second;
  24. // 纹理为压缩纹理,且设备不支持cocos的支持的所有压缩纹理
  25. if (info.compressed && !Configuration::getInstance()->supportsPVRTC()
  26. && !Configuration::getInstance()->supportsETC()
  27. && !Configuration::getInstance()->supportsS3TC()
  28. && !Configuration::getInstance()->supportsATITC())
  29. {
  30. CCLOG("cocos2d: WARNING: PVRTC/ETC images are not supported");
  31. return false;
  32. }
  33. if (mipmapsNum == 1 && !info.compressed) // 单张普通纹理的纹理内存对齐(在显存中内存对齐)
  34. {
  35. unsigned int bytesPerRow = pixelsWide * info.bpp / 8;
  36. if(bytesPerRow % 8 == 0) {
  37. glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
  38. }
  39. else if(bytesPerRow % 4 == 0) {
  40. glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  41. }
  42. else if(bytesPerRow % 2 == 0) {
  43. glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
  44. }
  45. else {
  46. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  47. }
  48. }
  49. else { // 其他情况,都不考虑内存对齐
  50. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  51. }
  52. if(_name != 0) // 删除先前的GL纹理
  53. {
  54. GL::deleteTexture(_name);
  55. _name = 0;
  56. }
  57. glGenTextures(1, &_name);
  58. GL::bindTexture2D(_name);
  59. // 单张纹理的MIN_FILTER:GL_LINEAR、GL_NEAREST
  60. // 多级纹理的MIN_FILETER参数:GL_LINEAR_MIPMAP_NEAREST、GL_NEAREST_MIPMAP_NEAREST
  61. if (mipmapsNum == 1)
  62. {
  63. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _antialiasEnabled ? GL_LINEAR : GL_NEAREST);
  64. }else
  65. {
  66. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _antialiasEnabled ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST);
  67. }
  68. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _antialiasEnabled ? GL_LINEAR : GL_NEAREST );
  69. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  70. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  71. #if CC_ENABLE_CACHE_TEXTURE_DATA
  72. if (_antialiasEnabled)
  73. {
  74. TexParams texParams = {(GLuint)(_hasMipmaps?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR),GL_LINEAR,GL_NONE,GL_NONE};
  75. VolatileTextureMgr::setTexParameters(this, texParams);
  76. }
  77. else
  78. {
  79. TexParams texParams = {(GLuint)(_hasMipmaps?GL_NEAREST_MIPMAP_NEAREST:GL_NEAREST),GL_NEAREST,GL_NONE,GL_NONE};
  80. VolatileTextureMgr::setTexParameters(this, texParams);
  81. }
  82. #endif
  83. // 检查前面GL调用的错误日志
  84. GLenum err = glGetError();
  85. if (err != GL_NO_ERROR)
  86. {
  87. cocos2d::log("OpenGL error 0x%04X in %s %s %d\n", err, __FILE__, __FUNCTION__, __LINE__);
  88. }
  89. int width = pixelsWide;
  90. int height = pixelsHigh;
  91. // Specify OpenGL texture image
  92. // 如果是多级纹理,无非就是多调用几次glTexImage2D,mipmapsNum=1就是普通单张纹理,也即调用一次glTexImage2D
  93. // 压缩纹理调用glCompressedTexImage2D
  94. // 非压缩纹理调用glTexImage2D
  95. for (int i = 0; i < mipmapsNum; ++i)
  96. {
  97. unsigned char *data = mipmaps[i].address;
  98. GLsizei datalen = mipmaps[i].len;
  99. if (info.compressed)
  100. {
  101. glCompressedTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, datalen, data);
  102. }
  103. else
  104. {
  105. glTexImage2D(GL_TEXTURE_2D, i, info.internalFormat, (GLsizei)width, (GLsizei)height, 0, info.format, info.type, data);
  106. }
  107. // 多级纹理必须是正方的,且必须是POT(2次幂尺寸的)
  108. if (i > 0 && (width != height || ccNextPOT(width) != width ))
  109. {
  110. CCLOG("cocos2d: Texture2D. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%d != height=%d", i, width, height);
  111. }
  112. // 检查前面GL调用的错误日志
  113. err = glGetError();
  114. if (err != GL_NO_ERROR)
  115. {
  116. CCLOG("cocos2d: Texture2D: Error uploading compressed texture level: %u . glError: 0x%04X", i, err);
  117. return false;
  118. }
  119. // 多级纹理,n+1级的尺寸=n级尺寸的1/2
  120. width = MAX(width >> 1, 1);
  121. height = MAX(height >> 1, 1);
  122. }
  123. _contentSize = Size((float)pixelsWide, (float)pixelsHigh);
  124. _pixelsWide = pixelsWide;
  125. _pixelsHigh = pixelsHigh;
  126. _pixelFormat = pixelFormat;
  127. _maxS = 1;
  128. _maxT = 1;
  129. _hasPremultipliedAlpha = false;
  130. _hasMipmaps = mipmapsNum > 1;
  131. // 指定使用的着色器,在调用draw***方法时。
  132. setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE));
  133. return true;
  134. }

initWithData

  1. // 通过void *data初始化纹理,其实本质就是mipmapsNum=1的mipmap
  2. bool Texture2D::initWithData(const void *data,
  3. ssize_t dataLen,
  4. Texture2D::PixelFormat pixelFormat,
  5. int pixelsWide,
  6. int pixelsHigh,
  7. const Size& /*contentSize*/) // 没鸟用
  8. {
  9. CCASSERT(dataLen>0 && pixelsWide>0 && pixelsHigh>0, "Invalid size");
  10. //if data has no mipmaps, we will consider it has only one mipmap
  11. MipmapInfo mipmap;
  12. mipmap.address = (unsigned char*)data;
  13. mipmap.len = static_cast<int>(dataLen);
  14. return initWithMipmaps(&mipmap, 1, pixelFormat, pixelsWide, pixelsHigh);
  15. }

initWithImage

  1. // 从一个image file 初始化纹理。 并将image format 转换成指定的texture format,比如png -> RGBA4444
  2. bool Texture2D::initWithImage(Image *image, PixelFormat format)
  3. {
  4. if (image == nullptr)
  5. {
  6. CCLOG("cocos2d: Texture2D. Can't create Texture. UIImage is nil");
  7. return false;
  8. }
  9. int imageWidth = image->getWidth();
  10. int imageHeight = image->getHeight();
  11. this->_filePath = image->getFilePath(); // image file的full path
  12. // 单张纹理大小有尺寸限制,glGetIntegerv(GL_MAX_TEXTURE_SIZE)获得
  13. Configuration *conf = Configuration::getInstance();
  14. int maxTextureSize = conf->getMaxTextureSize();
  15. if (imageWidth > maxTextureSize || imageHeight > maxTextureSize)
  16. {
  17. CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize);
  18. return false;
  19. }
  20. unsigned char* tempData = image->getData(); // image data
  21. size_t tempDataLen = image->getDataLen();
  22. Size imageSize = Size((float)imageWidth, (float)imageHeight);
  23. // pixelFormat表示我们需要纹理是什么格式的
  24. PixelFormat pixelFormat = ((PixelFormat::NONE == format) || (PixelFormat::AUTO == format)) ? image->getRenderFormat() : format;
  25. // renderFormat表示加载image file引擎默认转换的纹理格式
  26. PixelFormat renderFormat = image->getRenderFormat();
  27. if (image->getNumberOfMipmaps() > 1) // 多级纹理
  28. {
  29. // 如果是多级纹理,且不会转换成指定格式的纹理,在加载image file时是什么格式就是什么格式。
  30. if (pixelFormat != image->getRenderFormat())
  31. {
  32. CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format");
  33. }
  34. initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getRenderFormat(), imageWidth, imageHeight);
  35. // set the premultiplied tag
  36. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  37. return true;
  38. }
  39. else if (image->isCompressed()) //压缩纹理
  40. {
  41. // 暂不支持压缩纹理的格式转换
  42. if (pixelFormat != image->getRenderFormat())
  43. {
  44. CCLOG("cocos2d: WARNING: This image is compressed and we can't convert it for now");
  45. }
  46. initWithData(tempData, tempDataLen, image->getRenderFormat(), imageWidth, imageHeight, imageSize);
  47. // set the premultiplied tag
  48. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  49. return true;
  50. }
  51. else // 单张普通纹理,只有这种情况才支持转换成指定纹理格式
  52. {
  53. unsigned char* outTempData = nullptr;
  54. ssize_t outTempDataLen = 0;
  55. // 首先要从renderFormat纹理格式转换成我们指定的pixelFormat纹理格式
  56. pixelFormat = convertDataToFormat(tempData, tempDataLen, renderFormat, pixelFormat, &outTempData, &outTempDataLen);
  57. // 执行初始化
  58. initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize);
  59. if (outTempData != nullptr && outTempData != tempData) {
  60. free(outTempData);
  61. }
  62. // set the premultiplied tag
  63. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  64. return true;
  65. }
  66. }

initWithString

创建字体纹理。

  1. bool Texture2D::initWithString(
  2. const char *text, // A null terminated string.
  3. const std::string &fontName, // The font name.
  4. float fontSize, // The font size.
  5. const Size& dimensions = Size(0, 0), // The font dimension.
  6. TextHAlignment hAlignment = TextHAlignment::CENTER, // The font horizontal text alignment type.
  7. TextVAlignment vAlignment = TextVAlignment::TOP, // The font vertical text alignment type.
  8. bool enableWrap = true, // Whether enable text wrap or not.
  9. int overflow = 0); // Whether shrink font size when content larger than the dimensions.
  10. {
  11. FontDefinition tempDef;
  12. tempDef._shadow._shadowEnabled = false;
  13. tempDef._stroke._strokeEnabled = false;
  14. tempDef._fontName = fontName;
  15. tempDef._fontSize = fontSize;
  16. tempDef._dimensions = dimensions;
  17. tempDef._alignment = hAlignment;
  18. tempDef._vertAlignment = vAlignment;
  19. tempDef._fontFillColor = Color3B::WHITE;
  20. tempDef._enableWrap = enableWrap;
  21. tempDef._overflow = overflow;
  22. return initWithString(text, tempDef);
  23. }
  24. bool Texture2D::initWithString(const char *text, const FontDefinition& textDefinition)
  25. {
  26. if(!text || 0 == strlen(text))
  27. {
  28. return false;
  29. }
  30. #if CC_ENABLE_CACHE_TEXTURE_DATA
  31. // cache the texture data
  32. VolatileTextureMgr::addStringTexture(this, text, textDefinition);
  33. #endif
  34. bool ret = false;
  35. Device::TextAlign align;
  36. if (TextVAlignment::TOP == textDefinition._vertAlignment)
  37. {
  38. align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::TOP
  39. : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::TOP_LEFT : Device::TextAlign::TOP_RIGHT;
  40. }
  41. else if (TextVAlignment::CENTER == textDefinition._vertAlignment)
  42. {
  43. align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::CENTER
  44. : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::LEFT : Device::TextAlign::RIGHT;
  45. }
  46. else if (TextVAlignment::BOTTOM == textDefinition._vertAlignment)
  47. {
  48. align = (TextHAlignment::CENTER == textDefinition._alignment) ? Device::TextAlign::BOTTOM
  49. : (TextHAlignment::LEFT == textDefinition._alignment) ? Device::TextAlign::BOTTOM_LEFT : Device::TextAlign::BOTTOM_RIGHT;
  50. }
  51. else
  52. {
  53. CCASSERT(false, "Not supported alignment format!");
  54. return false;
  55. }
  56. #if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) && (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
  57. CCASSERT(textDefinition._stroke._strokeEnabled == false, "Currently stroke only supported on iOS and Android!");
  58. #endif
  59. PixelFormat pixelFormat = g_defaultAlphaPixelFormat; // 字体纹理采用默认纹理格式
  60. unsigned char* outTempData = nullptr;
  61. ssize_t outTempDataLen = 0;
  62. int imageWidth;
  63. int imageHeight;
  64. auto textDef = textDefinition;
  65. auto contentScaleFactor = CC_CONTENT_SCALE_FACTOR();
  66. textDef._fontSize *= contentScaleFactor;
  67. textDef._lineSpacing *= contentScaleFactor;
  68. textDef._dimensions.width *= contentScaleFactor;
  69. textDef._dimensions.height *= contentScaleFactor;
  70. textDef._stroke._strokeSize *= contentScaleFactor;
  71. textDef._shadow._shadowEnabled = false;
  72. bool hasPremultipliedAlpha;
  73. // 获取纹理数据,分平台实现
  74. Data outData = Device::getTextureDataForText(text, textDef, align, imageWidth, imageHeight, hasPremultipliedAlpha);
  75. if(outData.isNull())
  76. {
  77. return false;
  78. }
  79. Size imageSize = Size((float)imageWidth, (float)imageHeight);
  80. // 转换纹理格式,cocos 3.17版本pixelFormat=AUTO,表示无需转换格式,使用默认格式
  81. // 从这里我们也知道,字体纹理的格式默认看成是RGBA8888
  82. pixelFormat = convertDataToFormat(outData.getBytes(), imageWidth*imageHeight*4, PixelFormat::RGBA8888, pixelFormat, &outTempData, &outTempDataLen);
  83. ret = initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize);
  84. if (outTempData != nullptr && outTempData != outData.getBytes())
  85. {
  86. free(outTempData);
  87. }
  88. _hasPremultipliedAlpha = hasPremultipliedAlpha;
  89. return ret;
  90. }

3、更新纹理

  1. // 用data的数据更新纹理的这块子区域:
  2. // x: [offsetX, offsetX + width - 1]
  3. // y: [offsetY, offsetY + height - 1]
  4. bool Texture2D::updateWithData(const void *data,int offsetX,int offsetY,int width,int height)
  5. {
  6. if (_name)
  7. {
  8. GL::bindTexture2D(_name);
  9. const PixelFormatInfo& info = _pixelFormatInfoTables.at(_pixelFormat);
  10. glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, info.format, info.type, data);
  11. return true;
  12. }
  13. return false;
  14. }

4、删除纹理

  1. // 方法一
  2. Texture2D::~Texture2D() // 析构时,清除显存纹理
  3. {
  4. ......
  5. if(_name)
  6. {
  7. GL::deleteTexture(_name); // glDeleteTexture清除显存纹理。
  8. }
  9. }
  10. // 方法二
  11. void Texture2D::releaseGLTexture()
  12. {
  13. if(_name)
  14. {
  15. GL::deleteTexture(_name);
  16. }
  17. _name = 0;
  18. }

四、抗锯齿

注意与多重采样扛锯齿区分,这里的抗锯齿是通过设置Filtering为GL_LINEAR来得到模糊抗锯齿效果。

1、setAntiAliasTexParameters

  1. // 开启抗锯齿,其实就是;
  2. // - GL_TEXTURE_MIN_FILTER = GL_LINEAR
  3. // - GL_TEXTURE_MAG_FILTER = GL_LINEAR
  4. void Texture2D::setAntiAliasTexParameters()
  5. {
  6. if ( _antialiasEnabled )
  7. {
  8. return;
  9. }
  10. _antialiasEnabled = true;
  11. if (_name == 0)
  12. {
  13. return;
  14. }
  15. GL::bindTexture2D( _name );
  16. if( ! _hasMipmaps )
  17. {
  18. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  19. }
  20. else
  21. {
  22. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
  23. }
  24. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  25. #if CC_ENABLE_CACHE_TEXTURE_DATA
  26. TexParams texParams = {(GLuint)(_hasMipmaps?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR),GL_LINEAR,GL_NONE,GL_NONE};
  27. VolatileTextureMgr::setTexParameters(this, texParams);
  28. #endif
  29. }

2、setAliasTexParameters

  1. // 关闭扛锯齿,其实就是;
  2. // - GL_TEXTURE_MIN_FILTER = GL_NEAREST
  3. // - GL_TEXTURE_MAG_FILTER = GL_NEAREST
  4. void Texture2D::setAliasTexParameters()
  5. {
  6. if (! _antialiasEnabled)
  7. {
  8. return;
  9. }
  10. _antialiasEnabled = false;
  11. if (_name == 0)
  12. {
  13. return;
  14. }
  15. GL::bindTexture2D( _name );
  16. if( ! _hasMipmaps )
  17. {
  18. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  19. }
  20. else
  21. {
  22. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
  23. }
  24. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  25. #if CC_ENABLE_CACHE_TEXTURE_DATA
  26. TexParams texParams = {(GLuint)(_hasMipmaps?GL_NEAREST_MIPMAP_NEAREST:GL_NEAREST),GL_NEAREST,GL_NONE,GL_NONE};
  27. VolatileTextureMgr::setTexParameters(this, texParams);
  28. #endif
  29. }

默认是开启抗锯齿:

  1. Texture2D::Texture2D()
  2. ......
  3. , _antialiasEnabled(true)
  4. ......
  5. {
  6. }

3、多重采样抗锯齿

OpenGL多重采样抗锯齿知识
cocos中默认不开启多重采样。
cocos如何开启多重采样:

  1. //*****************AppDelegate.h
  2. // if you want a different context, modify the value of glContextAttrs
  3. // it will affect all platforms
  4. void AppDelegate::initGLContextAttrs()
  5. {
  6. // set OpenGL context attributes: red,green,blue,alpha,depth,stencil
  7. GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8, 0};
  8. GLView::setGLContextAttrs(glContextAttrs);
  9. }
  10. //*****************CCGLView.h
  11. struct GLContextAttrs
  12. {
  13. int redBits;
  14. int greenBits;
  15. int blueBits;
  16. int alphaBits;
  17. int depthBits;
  18. int stencilBits;
  19. int multisamplingCount; // 采样数量
  20. // 默认为0,即不开启多重采样
  21. // 大于0,表示开启多重采样
  22. };
  23. //*****************glview.h
  24. #define GL_MAX_SAMPLES 0x8D57 //最大采样数

五、动态多级纹理

通过前面initWithMipmaps源码的学习,我们知道,引擎默认是采用静态多级纹理模式,也即是在程序外部借助工具预生成多级纹理,这样可以提高性能。
另外我们也可以通过glGenerateMipmap在运行时动态生成多级纹理,这很方便但也损耗性能。

  1. void Texture2D::generateMipmap()
  2. {
  3. // 只支持2次幂纹理
  4. CCASSERT(_pixelsWide == ccNextPOT(_pixelsWide) && _pixelsHigh == ccNextPOT(_pixelsHigh), "Mipmap texture only works in POT textures");
  5. GL::bindTexture2D( _name );
  6. glGenerateMipmap(GL_TEXTURE_2D);
  7. _hasMipmaps = true;
  8. #if CC_ENABLE_CACHE_TEXTURE_DATA
  9. VolatileTextureMgr::setHasMipmaps(this, _hasMipmaps);
  10. #endif
  11. }

六、设置纹理参数

  1. // 从下面我们可以看到,支持设置以下纹理参数
  2. // 过滤:GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTER
  3. // 封装:GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T
  4. typedef struct _TexParams {
  5. GLuint minFilter;
  6. GLuint magFilter;
  7. GLuint wrapS;
  8. GLuint wrapT;
  9. } TexParams;
  10. void Texture2D::setTexParameters(const TexParams &texParams)
  11. {
  12. CCASSERT((_pixelsWide == ccNextPOT(_pixelsWide) || texParams.wrapS == GL_CLAMP_TO_EDGE) &&
  13. (_pixelsHigh == ccNextPOT(_pixelsHigh) || texParams.wrapT == GL_CLAMP_TO_EDGE),
  14. "GL_CLAMP_TO_EDGE should be used in NPOT dimensions");
  15. GL::bindTexture2D( _name );
  16. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texParams.minFilter );
  17. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texParams.magFilter );
  18. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParams.wrapS );
  19. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParams.wrapT );
  20. #if CC_ENABLE_CACHE_TEXTURE_DATA
  21. VolatileTextureMgr::setTexParameters(this, texParams);
  22. #endif
  23. }

七、手动OpenGL绘制

drawAtPoint

  1. // 以point为左下角点,绘制一张矩形纹理,宽高为纹理的宽高。
  2. void Texture2D::drawAtPoint(const Vec2& point)
  3. {
  4. GLfloat width = (GLfloat)_pixelsWide * _maxS,
  5. GLfloat height = (GLfloat)_pixelsHigh * _maxT;
  6. // 我们可以发现,是将纹理的Y方向倒置然后映射到顶点坐标构成的矩形上 。
  7. GLfloat coordinates[] = {
  8. 0.0f, _maxT, // 纹理左上角 -> 顶点矩形区域左下角
  9. _maxS, _maxT, // 纹理右上角 -> 顶点矩形区域右下角
  10. 0.0f, 0.0f, // 纹理左下角 -> 顶点矩形区域左上角
  11. _maxS, 0.0f // 纹理右下角 -> 顶点矩形区域右上角
  12. };
  13. GLfloat vertices[] = {
  14. point.x, point.y,
  15. width + point.x, point.y,
  16. point.x, height + point.y,
  17. width + point.x, height + point.y };
  18. // 启用用于绘制纹理的shader
  19. _shaderProgram->use();
  20. _shaderProgram->setUniformsForBuiltins();
  21. // 绑定纹理
  22. GL::bindTexture2D( _name );
  23. // 设置顶点属性
  24. GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_TEX_COORD );
  25. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  26. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
  27. // 绘制三角形带,顶点绘制顺序如下:
  28. // 2 ----- 3
  29. // | \ |
  30. // | \ |
  31. // 0 ----- 1
  32. // 构成两个三角形012和123。
  33. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  34. }

drawInRect

  1. // 将纹理绘制到rect指定的矩形区域
  2. // 和drawAtPoint的区别是,前者只指定了绘制位置,而drawInRect同时还指定了绘制的宽高
  3. void Texture2D::drawInRect(const Rect& rect)
  4. {
  5. GLfloat coordinates[] = {
  6. 0.0f, _maxT,
  7. _maxS, _maxT,
  8. 0.0f, 0.0f,
  9. _maxS, 0.0f
  10. };
  11. // 和drawAtPoint的区别就在这里,矩形区域的宽高不同。
  12. GLfloat vertices[] = {
  13. rect.origin.x, rect.origin.y, /*0.0f,*/
  14. rect.origin.x + rect.size.width, rect.origin.y, /*0.0f,*/
  15. rect.origin.x, rect.origin.y + rect.size.height, /*0.0f,*/
  16. rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, /*0.0f*/ };
  17. // 启用用于绘制纹理的shader
  18. _shaderProgram->use();
  19. _shaderProgram->setUniformsForBuiltins();
  20. // 绑定纹理
  21. GL::bindTexture2D( _name );
  22. // 设置顶点属性
  23. GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_TEX_COORD );
  24. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  25. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
  26. // 绘制同上
  27. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  28. }

八、alpha预乘

场景:纹理支持alpha。
一般做法如下:

  1. // ****************************************
  2. // ****** C++ 代 码
  3. // ****************************************
  4. ......;
  5. glEnable(GL_BLEND);
  6. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  7. createTexture(......); // glTexImage2D加载纹理到显存
  8. ......; // 各种使用纹理
  9. // ****************************************
  10. // ****** 片段着色器代码
  11. // ****************************************
  12. uniform Sampler2D texture; // 纹理
  13. varying vec2 v_texCoord; // 纹理坐标
  14. void main() {
  15. vec3 texColor = texture2D(texture, v_texCoord);
  16. // 纹理的alpha值就在texColor.a中
  17. // 在后续的Blending阶段,将按如下公式计算片段的最终颜色值
  18. // (Rs, Gs, Bs) * As + (Rd, Gd, Bd) * (1 - As)
  19. // Rs: source片段的R值
  20. // As: source片段的alpha值
  21. // Rd: 目标片段的R值
  22. // 前后两部分都要进行计算。
  23. gl_FragColor = texColor;
  24. }

优化做法(alpha预乘):

  1. // ****************************************
  2. // ****** C++ 代 码
  3. // ****************************************
  4. ......;
  5. glEnable(GL_BLEND);
  6. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE代替GL_SRC_ALPHA
  7. createTextureEx(......); // 在这一步中,纹理的RGB值已经乘以了alpha值。
  8. ......; // 各种使用纹理
  9. // ****************************************
  10. // ****** 片段着色器代码
  11. // ****************************************
  12. uniform Sampler2D texture; // 纹理
  13. varying vec2 v_texCoord; // 纹理坐标
  14. void main() {
  15. vec3 texColor = texture2D(texture, v_texCoord);
  16. // 在后续的Blending阶段,将按如下公式计算片段的最终颜色值
  17. // (Rs, Gs, Bs) * 1 + (Rd, Gd, Bd) * (1 - As)
  18. // 省去了(Rs, Gs, Bs) * As的计算工作,提升了性能。
  19. gl_FragColor = texColor;
  20. }

相关源码:

  1. Texture2D::Texture2D()
  2. ......
  3. , _hasPremultipliedAlpha(false) // 纹理默认不开启alpha预乘
  4. ......
  5. {
  6. }
  7. // 从下面几个函数的相关源码,我们可以看出,只有在加载字体纹理和通过Image初始化纹理时,才可能支持alpha预乘。
  8. bool Texture2D::initWithMipmaps(......)
  9. {
  10. ......
  11. _hasPremultipliedAlpha = false;
  12. ......
  13. }
  14. bool Texture2D::initWithImage(Image *image, PixelFormat format)
  15. {
  16. ......
  17. if (image->getNumberOfMipmaps() > 1) {
  18. ......
  19. initWithMipmaps(......);
  20. ......
  21. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  22. ......
  23. }
  24. else if (image->isCompressed()) {
  25. ......
  26. initWithData(......);
  27. ......
  28. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  29. ......
  30. }
  31. else {
  32. ......
  33. initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize);
  34. ......
  35. _hasPremultipliedAlpha = image->hasPremultipliedAlpha();
  36. ......
  37. }
  38. }
  39. bool Texture2D::initWithString(const char *text, const FontDefinition& textDefinition)
  40. {
  41. ......
  42. bool hasPremultipliedAlpha;
  43. Data outData = Device::getTextureDataForText(......, hasPremultipliedAlpha);
  44. ret = initWithData(......);
  45. _hasPremultipliedAlpha = hasPremultipliedAlpha;
  46. return ret;
  47. }
  48. /// halx99 spec, ANDROID ETC1 ALPHA supports.
  49. // 这个函数主要是用于增加ETC1压缩纹理的alpha支持,ETC1本身是不支持alpha的。
  50. // 实现方法就是额外添加一张同大小的alpha纹理,与原纹理混合,从而达到alpha效果。
  51. void Texture2D::setAlphaTexture(Texture2D* alphaTexture)
  52. {
  53. if (alphaTexture != nullptr) { // 这张纹理其实就保存在了上面着色器代码中的texture_alpha
  54. alphaTexture->retain();
  55. CC_SAFE_RELEASE(_alphaTexture);
  56. _alphaTexture = alphaTexture;
  57. _hasPremultipliedAlpha = true; // 采用alpha预乘,提升性能
  58. }
  59. }

ETC1添加alpha支持

ETC1压缩纹理并不支持alpha,通过额外添加一张相同大小的alpha纹理,并与原纹理混合,从而达到支持alpha的效果,具体实现原理如下:

  1. // ****************************************
  2. // ****** C++ 代 码
  3. // ****************************************
  4. ......;
  5. glEnable(GL_BLEND);
  6. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // 使用alpha预乘
  7. ......;
  8. // ****************************************
  9. // ****** 片段着色器代码
  10. // ****************************************
  11. uniform Sampler2D texture; // 纹理
  12. uniform Sampler2D texture_alpha; // alpha纹理,GL_RED格式,即用R分量保存alpha值
  13. varying vec2 v_texCoord; // 纹理坐标
  14. void main() {
  15. float alpha = texture2D(texture_alpha, v_texCoord).r;
  16. vec3 texColor = vec4(texture2D(texture, v_texCoord).rgb, alpha);
  17. texColor.rgb *= alpha; // 在这里提前将源片段颜色值与alpha相乘,在后面的混合阶段,就无需在乘以alpha了。
  18. gl_FragColor = texColor;
  19. }
  20. void Texture2D::setAlphaTexture(Texture2D* alphaTexture)
  21. {
  22. if (alphaTexture != nullptr) // 就对应上面的texture_alpha 采样器
  23. {
  24. alphaTexture->retain();
  25. CC_SAFE_RELEASE(_alphaTexture);
  26. _alphaTexture = alphaTexture;
  27. _hasPremultipliedAlpha = true; // PremultipliedAlpha should be true.
  28. }
  29. }

九、纹理内存计算

工具检测

XCode的OpenGL ES Analytics工具可以检测纹理占用大小。

程序计算

工具检测不够灵活、不够精细,无能实时检测程序各个时间点的内存占用情况,并关联到具体的纹理上。我们可以自己进行计算:

  1. // textureBytes: 纹理内存占用大小(字节数)
  2. // size: 纹理像素宽高
  3. // bpp: 每像素的bit数(bits per pixel)
  4. textureBytes = size.width * size.height * bpp >> 3;

cocos中各纹理格式的BPP如下:

格式 bpp 是否支持alpha
BGRA8888 32
RGBA8888 32
RGB888 24
RGB565 16
A8 8
I8 8
AI88 16
RGBA4444 16
RGB5A1 16 1 bit alpha
PVRTC4 4
PVRTC4A 4
PVRTC2 2
PVRTC2A 2
ETC 4
S3TC_DXT1 4 1 bit alpha
S3TC_DXT3 8
S3TC_DXT5 8
ATC_RGB 4
ATC_EXPLICIT_ALPHA 8
ATC_INTERPOLATED_ALPHA 8

注意多级纹理的计算,外部工具预生成的多级纹理,按上面的公式正常计算,OpenGL ES命令(glGenerateMipmap)生成的多级纹理,则还需要额外计算每级纹理的内存。