标签:
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缓存中读取,
而不用重走上面流程,从而达到缓存的目的。
标签:
原文地址:http://blog.csdn.net/tianxiawuzhei/article/details/45482465