CCTextureCache类源码分析 (1)
CCTextureCache类源码分析(1): 1、 CCTextureCache类: 这个类跟纹理缓存有关,我们跟着代码分析下这个类是怎么对纹理进行缓存的。 /** Returns the shared instance of the cache * 单例 */ static CCTextureCache * sharedTextureCache(); 2、我们在创建精灵的时候会调用 CCTextureCache::sharedTextureCache()->addImage(pszFilename); 方法,加载精灵的纹理。 addImage --函数分析: CCTexture2D * CCTextureCache::addImage(const char * path) { CCAssert(path != NULL, "TextureCache: fileimage MUST not be NULL"); CCTexture2D * texture = NULL; CCImage* pImage = NULL; // Split up directory and filename // MUTEX: // Needed since addImageAsync calls this method from a different thread //pthread_mutex_lock(m_pDictLock); std::string pathKey = path; //获取文件的全路径 pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(pathKey.c_str()); if (pathKey.size() == 0) { return NULL; } //CCDictionary* m_pTextures; 成员变量,字典类型,用来存放已经加载的纹理 //如果某个纹理加载过,这就会存放到这个字典中,那么下次就直接从这个 //字典中找到就可以了 texture = (CCTexture2D*)m_pTextures->objectForKey(pathKey.c_str()); std::string fullpath = pathKey; // (CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(path)); if (! texture) //如果这个纹理是个新的纹理(以前没有加载过,则需要加载) { //把pathKey即纹理的全路径转化为小写 std::string lowerCase(pathKey); for (unsigned int i = 0; i < lowerCase.length(); ++i) { lowerCase[i] = tolower(lowerCase[i]); } // all images are handled by UIImage except PVR extension that is handled by our own handler do { //如果纹理格式是.pvr,这是用addPVRImage方法加载,后面分析 if (std::string::npos != lowerCase.find(".pvr")) { texture = this->addPVRImage(fullpath.c_str()); } //如果纹理格式是.pkm,这是用addETCImage方法加载,后面分析 else if (std::string::npos != lowerCase.find(".pkm")) { // ETC1 file format, only supportted on Android texture = this->addETCImage(fullpath.c_str()); } else //其他纹理格式,使用下面的方法加载 { //先判断图片格式 CCImage::EImageFormat eImageFormat = CCImage::kFmtUnKnown; if (std::string::npos != lowerCase.find(".png")) { eImageFormat = CCImage::kFmtPng; } else if (std::string::npos != lowerCase.find(".jpg") || std::string::npos != lowerCase.find(".jpeg")) { eImageFormat = CCImage::kFmtJpg; } else if (std::string::npos != lowerCase.find(".tif") || std::string::npos != lowerCase.find(".tiff")) { eImageFormat = CCImage::kFmtTiff; } else if (std::string::npos != lowerCase.find(".webp")) { eImageFormat = CCImage::kFmtWebp; } //CCImage解析各种格式图片的类,各个平台下有些实现方法不同 //跟平台相关,这个类也后面分析,这里只需要知道,这个类会根据不同 //的图片格式,去解析图片数据,把图片数据加载到内存中,继承子CCObject pImage = new CCImage(); CC_BREAK_IF(NULL == pImage); bool bRet = pImage->initWithImageFile(fullpath.c_str(), eImageFormat); CC_BREAK_IF(!bRet); //纹理类,继承自CCObject,此时引用计数 1, //注意:这里并没有加入到自动释放池中 texture = new CCTexture2D(); //根据上面得到的CCImage初始化texture if( texture && texture->initWithImage(pImage) ) { #if CC_ENABLE_CACHE_TEXTURE_DATA //这个先不用关,跟android有关 // cache the texture file name VolatileTexture::addImageTexture(texture, fullpath.c_str(), eImageFormat); #endif //得的texture纹理后,缓存到m_pTextures字典中,引用计数 +1 = 2 m_pTextures->setObject(texture, pathKey.c_str()); texture->release(); //引用计数 -1 = 1 } else { CCLOG("cocos2d: Couldn't create texture for file:%s in CCTextureCache", path); } } } while (0); } //释放pImage(CCImage),通过上面的initWithImage函数,我们 //得到了所需要的纹理,所以这里的CCImage类就可以释放了。 CC_SAFE_RELEASE(pImage); //pthread_mutex_unlock(m_pDictLock); return texture; } 3、根据CCImage初始化texture if( texture && texture->initWithImage(pImage) ) ------ >> bool CCTexture2D::initWithImage(CCImage *uiImage) { if (uiImage == NULL) { CCLOG("cocos2d: CCTexture2D. Can't create Texture. UIImage is nil"); return false; } unsigned int imageWidth = uiImage->getWidth(); unsigned int imageHeight = uiImage->getHeight(); CCConfiguration *conf = CCConfiguration::sharedConfiguration(); //纹理有个最大尺寸,判断是否超过最大尺寸 unsigned maxTextureSize = conf->getMaxTextureSize(); if (imageWidth > maxTextureSize || imageHeight > maxTextureSize) { CCLOG("cocos2d: WARNING: Image (%u x %u) is bigger than the supported %u x %u", imageWidth, imageHeight, maxTextureSize, maxTextureSize); return false; } // always load premultiplied images return initPremultipliedATextureWithImage(uiImage, imageWidth, imageHeight); } -->>initPremultipliedATextureWithImage函数: bool CCTexture2D::initPremultipliedATextureWithImage(CCImage *image, unsigned int width, unsigned int height) { unsigned char* tempData = image->getData(); //图片数据 unsigned int* inPixel32 = NULL; unsigned char* inPixel8 = NULL; unsigned short* outPixel16 = NULL; bool hasAlpha = image->hasAlpha(); //是否有alpha分量 CCSize imageSize = CCSizeMake((float)(image->getWidth()), (float)(image->getHeight())); CCTexture2DPixelFormat pixelFormat; //纹理格式 size_t bpp = image->getBitsPerComponent(); // compute pixel format // 根据是否有alpha分量,设置纹理格式 if (hasAlpha) { // If the image has alpha, you can create RGBA8 (32-bit) or RGBA4 (16-bit) or RGB5A1 (16-bit) // Default is: RGBA8888 (32-bit textures) //static CCTexture2DPixelFormat g_defaultAlphaPixelFormat = kCCTexture2DPixelFormat_Default; //默认纹理格式RGBA8888 //这里可以通过setDefaultAlphaPixelFormat函数进行设置,而且在 //void CCDirector::setDefaultValues(void)函数中,会根据CCConfiguration类中的 //配置进行设置。 /* // // Texture options for images that contains alpha // // implementation CCTexture2D (PixelFormat) void CCTexture2D::setDefaultAlphaPixelFormat(CCTexture2DPixelFormat format) { g_defaultAlphaPixelFormat = format; } */ pixelFormat = g_defaultAlphaPixelFormat; } else { if (bpp >= 8) { pixelFormat = kCCTexture2DPixelFormat_RGB888; } else { pixelFormat = kCCTexture2DPixelFormat_RGB565; } } // Repack the pixel data into the right format //这里所做的工作:把图片数据 转化为 响应纹理格式的数据 //从这里 // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" //可以看出来,我们的从image->getData()得到的图片数据都是每个颜色分量都有8位的 //数据格式,只不过有些数据有alpha分量,有些没有alpha分量 // width(图片宽度) * height(图片高度) unsigned int length = width * height; if (pixelFormat == kCCTexture2DPixelFormat_RGB565) { if (hasAlpha) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" tempData = new unsigned char[width * height * 2]; outPixel16 = (unsigned short*)tempData; inPixel32 = (unsigned int*)image->getData(); for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B } } else { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB" tempData = new unsigned char[width * height * 2]; outPixel16 = (unsigned short*)tempData; inPixel8 = (unsigned char*)image->getData(); for(unsigned int i = 0; i < length; ++i) { *outPixel16++ = (((*inPixel8++ & 0xFF) >> 3) << 11) | // R (((*inPixel8++ & 0xFF) >> 2) << 5) | // G (((*inPixel8++ & 0xFF) >> 3) << 0); // B } } } else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" inPixel32 = (unsigned int*)image->getData(); tempData = new unsigned char[width * height * 2]; outPixel16 = (unsigned short*)tempData; for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A } } else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" inPixel32 = (unsigned int*)image->getData(); tempData = new unsigned char[width * height * 2]; outPixel16 = (unsigned short*)tempData; for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A } } else if (pixelFormat == kCCTexture2DPixelFormat_A8) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "AAAAAAAA" inPixel32 = (unsigned int*)image->getData(); tempData = new unsigned char[width * height]; unsigned char *outPixel8 = tempData; for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel8++ = (*inPixel32 >> 24) & 0xFF; // A } } if (hasAlpha && pixelFormat == kCCTexture2DPixelFormat_RGB888) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB" inPixel32 = (unsigned int*)image->getData(); tempData = new unsigned char[width * height * 3]; unsigned char *outPixel8 = tempData; for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B } } //看下面 initWithData(tempData, pixelFormat, width, height, imageSize); if (tempData != image->getData()) { delete [] tempData; } m_bHasPremultipliedAlpha = image->isPremultipliedAlpha(); return true; } ----initWithData--->> bool CCTexture2D::initWithData(const void *data, CCTexture2DPixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const CCSize& contentSize) { unsigned int bitsPerPixel; //Hack: bitsPerPixelForFormat returns wrong number for RGB_888 textures. See function. //根据纹理格式,得到每个像素需要多少位 if(pixelFormat == kCCTexture2DPixelFormat_RGB888) { bitsPerPixel = 24; } else { bitsPerPixel = bitsPerPixelForFormat(pixelFormat); } unsigned int bytesPerRow = pixelsWide * bitsPerPixel / 8; //glPixelStore这组函数要改变的是像素的存储格式(摘自网路,OpenGL的东西,我也不太明白) if(bytesPerRow % 8 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 8); } else if(bytesPerRow % 4 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else if(bytesPerRow % 2 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 2); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } //下面这些都是OpenGL纹理相关的内容,我现在也不是很清楚 glGenTextures(1, &m_uName); ccGLBindTexture2D(m_uName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_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 ); // Specify OpenGL texture image switch(pixelFormat) { case kCCTexture2DPixelFormat_RGBA8888: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGB888: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGBA4444: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); break; case kCCTexture2DPixelFormat_RGB5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); break; case kCCTexture2DPixelFormat_RGB565: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); break; case kCCTexture2DPixelFormat_AI88: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_I8: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); break; default: CCAssert(0, "NSInternalInconsistencyException"); } m_tContentSize = contentSize; m_uPixelsWide = pixelsWide; m_uPixelsHigh = pixelsHigh; m_ePixelFormat = pixelFormat; m_fMaxS = contentSize.width / (float)(pixelsWide); m_fMaxT = contentSize.height / (float)(pixelsHigh); m_bHasPremultipliedAlpha = false; m_bHasMipmaps = false; setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture)); return true; }
总结:
在CCTextureCache类中通过 m_pTextures 字典类型的成员变量存放加载过的
纹理CCTexture2D,以后如果再次加载相同的纹理,直接去m_pTextures缓存中读取,
而不用重走上面流程,从而达到缓存的目的。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。