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缓存中读取,

而不用重走上面流程,从而达到缓存的目的。

时间: 2024-07-29 04:04:44

CCTextureCache类源码分析 (1)的相关文章

CCTextureCache类源码分析(2)

CCTextureCache类源码分析(2): 在CCTextureCache类源码分析(1)中,我们分析了CCTextureCache如何实现 纹理缓存的,但是在分析的过程中,我们忽略了很多东西,比如CCImage类 如何加载纹理图片,这一篇我们分析一下CCImage: 源码分析: 1.CCImage继承自CCObject 2.成员变量,这些变量需要我们通过解析图片文件获得 unsigned char *m_pData; //图片数据 CC_SYNTHESIZE_READONLY(unsign

List 接口以及实现类和相关类源码分析

List 接口以及实现类和相关类源码分析 List接口分析 接口描述 用户可以对列表进行随机的读取(get),插入(add),删除(remove),修改(set),也可批量增加(addAll),删除(removeAll,retainAll),获取(subList). 还有一些判定操作:包含(contains[All]),相等(equals),索引(indexOf,lastIndexOf),大小(size). 还有获取元素类型数组的操作:toArray() 注意事项 两种迭代器Iterator和L

2020了你还不会Java8新特性?(四)Collector类源码分析

Collector类源码分析 jdk8是怎么对底层完成支持的.不了解底层,平时用还可以,但是遇到问题的时候就会卡在那里.迟迟灭有解决方案.在学习一门新技术时,先学习怎么去用,不要执着于源码.但是随着用的越来越多,你去了解底层是比较好的一种学习方法. 有多种方法可以实现同一个功能.什么方式更好呢? 越具体的方法越好. 减少自动装箱拆箱操作 collect : 收集器 Collector作为collect方法的参数. Collector作为一个接口.它是一个可变的汇聚操作,将输入元素累计到一个可变的

Cocos2d-X3.0 刨根问底(六)----- 调度器Scheduler类源码分析

上一章,我们分析Node类的源码,在Node类里面耦合了一个 Scheduler 类的对象,这章我们就来剖析Cocos2d-x的调度器 Scheduler 类的源码,从源码中去了解它的实现与应用方法. 直入正题,我们打开CCScheduler.h文件看下里面都藏了些什么. 打开了CCScheduler.h 文件,还好,这个文件没有ccnode.h那么大有上午行,不然真的吐血了, 仅仅不到500行代码.这个文件里面一共有五个类的定义,老规矩,从加载的头文件开始阅读. #include <funct

Cocos2d-X3.0 刨根问底(三)----- Director类源码分析

上一章我们完整的跟了一遍HelloWorld的源码,了解了Cocos2d-x的启动流程.其中Director这个类贯穿了整个Application程序,这章随小鱼一起把这个类分析透彻. 小鱼的阅读源码的习惯是,一层层地分析代码,在阅读Director这个类的时候,碰到了很多其它的Cocos2d-x类,我的方式是先大概了解一下类的作用,完整的去了解Director类,之后再去按照重要程度去分析碰到的其它类. 一点一点分析 CCDirector.h #ifndef __CCDIRECTOR_H__

C++卷积神经网络实例:tiny_cnn代码详解(11)——层结构容器layers类源码分析

在这篇博文中我们对tiny_cnn卷积神经网络模型中的最后一个网络结构方面的类--layers做简要分析. 首先,layers通俗的讲可以被称为是层结构的vector,即层结构容器.由于卷积神经网络是一个多层的网络模型,因此有必要将网络中各个层进行统一管理,这便引出了本篇博文中所要介绍的layers类.layers类是一个vector类型的变量,其中压入的元素就是网络中的各个层模型,这里给出一个简单的结构图,一目了然: 从上图中可以清晰的看到layers的vector结构,说白了就是一个层结构类

Request类源码分析

通过APIView进入找到Request的源码 可以看见一堆属性和方法,其中request.data其实是一个方法,被包装成一个属性 继续看__getattr__和query_params方法: 代码总结: Request其实就是原生request对象被包装后的Request,即重写了__getattr__,return getattr(self._request, attr) 比如:print(request.GET)就当于print(request.query_params) 原文地址:ht

Boolean类源码分析

Boolean类里面的常量: Boolean.TRUE:这个是调用Boolean的构造函数,新建了一个Boolean对象,所以TRUE是Boolean类型的.用来避免每次都创建新的Boolean对象,可以通过Boolean b =  Boolean.TRUE; public static finalBoolean TRUE = new Boolean(true); Boolean.FALSE:这个是调用Boolean的构造函数,新建了一个Boolean对象,所以FALSE是Boolean类型的.

Launcher类源码分析

基于上一次获取系统类加载器这块进行分析: 关于这个方法的javadoc在之前已经阅读过了,不过这里再来仔细阅读一下加深印象: 这里有一个非常重要的概念:上下文类加载器: 它的作用非常之大,在后面会详细进行学习,先有个印象. 接着来看一下它的具体实现: 再来看一下是如何初始化的: 所以接下来将焦点定位到获取Launcher实例上: 那有没有办法获得它的源代码呢?当然有,这里就需要用到一个开源版本的JDK,叫Open Jdk,它跟Oracle的JDK90%以上的代码是一模一样的,它的网站是:open