CCTextureCache类源码分析(2)

CCTextureCache类源码分析(2):

在CCTextureCache类源码分析(1)中,我们分析了CCTextureCache如何实现
纹理缓存的,但是在分析的过程中,我们忽略了很多东西,比如CCImage类
如何加载纹理图片,这一篇我们分析一下CCImage:

源码分析:
    1、CCImage继承自CCObject
    2、成员变量,这些变量需要我们通过解析图片文件获得
	 unsigned char *m_pData; //图片数据
	 CC_SYNTHESIZE_READONLY(unsigned short,   m_nWidth,       Width); //宽高
	 CC_SYNTHESIZE_READONLY(unsigned short,   m_nHeight,      Height);
	 CC_SYNTHESIZE_READONLY(int,     m_nBitsPerComponent,   BitsPerComponent); //每个颜色分量的位数
	 bool m_bHasAlpha; //是否有alpha分量

    3、
    //对于.pvr 和 .pkm 图片格式文件需要特殊处理,后面分析
    if (std::string::npos != lowerCase.find(".pvr"))
    {
	texture = this->addPVRImage(fullpath.c_str());
    }
    else if (std::string::npos != lowerCase.find(".pkm"))
    {
	// ETC1 file format, only supportted on Android
	texture = this->addETCImage(fullpath.c_str());
    }
    else
    {
        //针对下面这些图片格式,我们需要使用CCImage类来读取
	//图片文件数据到内存中,并进行分析,因为每一种图片格式
	//文件对图片信息的存储方式是不同的,比如那几个字节存放图片的大小信息,
	//那些字节存放图片颜色信息,我们需要根据每种文件格式进行不同的分析处理,
	//从而得到我们需要的信息。
	//从这里也可以看出cocos2dx支持的图片格式:
	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;
	}

	pImage = new CCImage();
	CC_BREAK_IF(NULL == pImage);

	bool bRet = pImage->initWithImageFile(fullpath.c_str(), eImageFormat);
	CC_BREAK_IF(!bRet);

----initWithImageFile---->>
strPath : 文件路径
eImgFmt :  图片格式
bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = eFmtPng*/)
{
    bool bRet = false;

#ifdef EMSCRIPTEN
    ....这部分就不管了
#else
    //读取图片的文件数据
    unsigned long nSize = 0;
    std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(strPath);
    unsigned char* pBuffer = CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(), "rb", &nSize);
    if (pBuffer != NULL && nSize > 0)
    {
        bRet = initWithImageData(pBuffer, nSize, eImgFmt);
    }
    CC_SAFE_DELETE_ARRAY(pBuffer);
#endif // EMSCRIPTEN

    return bRet;
}

------initWithImageData------>>
bool CCImage::initWithImageData(void * pData,
                                int nDataLen,
                                EImageFormat eFmt/* = eSrcFmtPng*/,
                                int nWidth/* = 0*/,
                                int nHeight/* = 0*/,
                                int nBitsPerComponent/* = 8*/)
{
    bool bRet = false;
    do
    {
        CC_BREAK_IF(! pData || nDataLen <= 0);

	//根据图片文件格式,调用不同的解析函数
        if (kFmtPng == eFmt)
        {
            //对png图片进行解析,_initWithPngData函数里面调用png解析的库
	    //对png文件进行解析,然后得到我们所需的所有信息
            bRet = _initWithPngData(pData, nDataLen);
            break;
        }
        else if (kFmtJpg == eFmt)
        {
            bRet = _initWithJpgData(pData, nDataLen);
            break;
        }
        else if (kFmtTiff == eFmt)
        {
            bRet = _initWithTiffData(pData, nDataLen);
            break;
        }
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
       else if (kFmtWebp == eFmt)
        {
            bRet = _initWithWebpData(pData, nDataLen);
            break;
        }
#endif
        else if (kFmtRawData == eFmt)
        {
            bRet = _initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent, false);
            break;
        }
        else
        {
            // if it is a png file buffer.
            if (nDataLen > 8)
            {
                unsigned char* pHead = (unsigned char*)pData;
                if (   pHead[0] == 0x89
                    && pHead[1] == 0x50
                    && pHead[2] == 0x4E
                    && pHead[3] == 0x47
                    && pHead[4] == 0x0D
                    && pHead[5] == 0x0A
                    && pHead[6] == 0x1A
                    && pHead[7] == 0x0A)
                {
                    bRet = _initWithPngData(pData, nDataLen);
                    break;
                }
            }

            // if it is a tiff file buffer.
            if (nDataLen > 2)
            {
                unsigned char* pHead = (unsigned char*)pData;
                if (  (pHead[0] == 0x49 && pHead[1] == 0x49)
                    || (pHead[0] == 0x4d && pHead[1] == 0x4d)
                    )
                {
                    bRet = _initWithTiffData(pData, nDataLen);
                    break;
                }
            }

            // if it is a jpeg file buffer.
            if (nDataLen > 2)
            {
                unsigned char* pHead = (unsigned char*)pData;
                if (   pHead[0] == 0xff
                    && pHead[1] == 0xd8)
                {
                    bRet = _initWithJpgData(pData, nDataLen);
                    break;
                }
            }
        }
    } while (0);
    return bRet;
}

总结:

CCImage所做的工作就是根据不同的图片格式调用不同的底层库,

如png,jpg解析库,通过这些库对图片文件进行分析,

从而得到我们所需要的所有信息,这里有个疑惑,就是通过底层库

解析图片文件之后得到的数据到底是什么格式存储的?

因为我在CCTextureCache类源码分析(1) 通过下面这行

// Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA"

猜测数据的存储都是每个颜色分量是8位,但是因为我对png这些图片的解析不熟悉,

所以在这里并没有很好的证据证明上面的猜测,所以把这个疑惑记录在此。

时间: 2024-08-01 19:04:45

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

CCTextureCache类源码分析 (1)

CCTextureCache类源码分析(1): 1. CCTextureCache类: 这个类跟纹理缓存有关,我们跟着代码分析下这个类是怎么对纹理进行缓存的. /** Returns the shared instance of the cache * 单例 */ static CCTextureCache * sharedTextureCache(); 2.我们在创建精灵的时候会调用 CCTextureCache::sharedTextureCache()->addImage(pszFilen

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