cocos2d-x 源码剖析(15)
2014-03-10 14:32
288 查看
上节讲到了cocos2d-x在iOS上解压绝大数的图片格式为CCImage,然后再转化为纹理格式。其中有一个列外就是Webp格式。今天我们来看看Windows上面的情况,Android上的情况和Windows是类似的,都是使用第三方库来解码图片。按照道理来讲,Android上是可以采用类似iOS的技术,使用Android的系统库来解码图片,而且Android在4.0版本上已经开始原生支持Webp格式了。但是Android的系统库是Java的,如果要传到cocos2d-x中需要通过Jni调用,也就增加了不必要的麻烦。在早期cocos2d-x读取assets资源有严重的性能问题,本人采用了这个方法获得了巨大的性能提升。新的cocos2d-x读取assets的资源利用了缓存加速,性能和这种迂回的方式相差不多了。
好我们来看看windows平台下的CCImage文件,如果你是Mac系统,在xcode工程中是看不到这个文件的,但是你可以使用Sublime打开源码目录下面的文件自行查看。在Windows下面,CCImage的文件组织有点特别。除了platform下面的CCImage.h的头文件,和win32下面的CCImage.cpp文件以外,在platform下面还有两个额外的文件也就是CCImageCommon_cpp.h和CCImageCommonWebp.cpp文件。第一个文件也是源文件,命名为.h是可以通过条件编译导入到CCImage.cpp文件中,至于Webp文件要单独列出来,是因为iOS上也要用到这个文件。因为其他格式的图片解码和Webp的流程差不多,我们使用Webp作为讲解。还记得那个判断函数吗?在Windows下面他变成了这个样子:
如果是Webp格式的文件就采用下面这个函数初始化了:
这个方式很简单,采用Google提供的Webp库解码图片。当然也要包含其头文件和lib。
其他格式由其第三方库的使用方法不同而不同,就不再多说了。相对而已Webp是很简洁的。这便是cocos2d-x中解码图片所采用的方法。还有一点值得注意的是,CCImage将其拷贝构造函数声明为了私有方法,也就是说你不能利用CCImage来赋值,毕竟里面是一大块内存,使用赋值或者添加到容器中都是很愚蠢的行为。
CCImage还有几个比较有趣的功能,他提供了一个saveToFile的函数。我们知道CCImage可以从相当多的格式初始化,那个这个saveToFile就可以作为一个转化函数来使用了。它能将图片保存为png或者jpg的格式,注意这个函数默认是不保存透明的,如果需要可以将其第二个参数设置为true。你可以采用压缩的图片格式打包,然后在游戏第一次运行的时候将其保存为易于解码的格式,来达到游戏发布体积和加载速度上的平衡。CCImage就能简单的完成这个操作。
CCImage还有一个功能就是,它能从一个string初始化一个图片。另外IOS和Android还提供了一个initWithStringShadowStroke的功能。如果你要显示很有艺术感的字体,不妨用用这个函数。字体的渲染向来都是很恶心的内容,在Windows和Android上cocos2d-x采用了一个叫做BitmapDC的概念,再调用各自的平台特性来完成这个工作。在Android上是采用jni的方式调用系统的函数实现的。在iOS上直接采用了系统函数,没有借用BitmapDC这个概念。有一个问题就是,如果你在Android上开启了Debug模式,那么会输出相当多的JVM释放资源的信息,这是因为每一次信息改动都生成了一张显示图片,造成JVM频繁回收。这极大的影响了游戏性能。所以TTF文件使用在Android上是极其低效的,如果你要做聊天,这方面有很大的优化余地。
好我们来看看windows平台下的CCImage文件,如果你是Mac系统,在xcode工程中是看不到这个文件的,但是你可以使用Sublime打开源码目录下面的文件自行查看。在Windows下面,CCImage的文件组织有点特别。除了platform下面的CCImage.h的头文件,和win32下面的CCImage.cpp文件以外,在platform下面还有两个额外的文件也就是CCImageCommon_cpp.h和CCImageCommonWebp.cpp文件。第一个文件也是源文件,命名为.h是可以通过条件编译导入到CCImage.cpp文件中,至于Webp文件要单独列出来,是因为iOS上也要用到这个文件。因为其他格式的图片解码和Webp的流程差不多,我们使用Webp作为讲解。还记得那个判断函数吗?在Windows下面他变成了这个样子:
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) { 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; }
如果是Webp格式的文件就采用下面这个函数初始化了:
bool CCImage::_initWithWebpData(void*pData,intnDataLen) { bool bRet = false; do { WebPDecoderConfig config; if(WebPInitDecoderConfig(&config)==0)break; if(WebPGetFeatures((uint8_t*)pData,nDataLen,&config.input)!=VP8_STATUS_OK)break; if(config.input.width==0||config.input.height==0)break; config.output.colorspace=MODE_RGBA; m_nBitsPerComponent=8; m_nWidth = config.input.width; m_nHeight = config.input.height; m_bHasAlpha = true; int bufferSize = m_nWidth * m_nHeight * 4; m_pData = new unsigned char[bufferSize]; config.output.u.RGBA.rgba=(uint8_t*)m_pData; config.output.u.RGBA.stride=m_nWidth*4; config.output.u.RGBA.size=bufferSize; config.output.is_external_memory=1; if(WebPDecode((uint8_t*)pData,nDataLen,&config)!=VP8_STATUS_OK) { delete[]m_pData; m_pData=NULL; break; } bRet=true; }while(0); return bRet; }
这个方式很简单,采用Google提供的Webp库解码图片。当然也要包含其头文件和lib。
#if defined(__native_client__) || defined(EMSCRIPTEN) // TODO(sbc): I'm pretty sure all platforms should be including // webph headers in this way. #include "webp/decode.h" #else #include "decode.h" #endif
其他格式由其第三方库的使用方法不同而不同,就不再多说了。相对而已Webp是很简洁的。这便是cocos2d-x中解码图片所采用的方法。还有一点值得注意的是,CCImage将其拷贝构造函数声明为了私有方法,也就是说你不能利用CCImage来赋值,毕竟里面是一大块内存,使用赋值或者添加到容器中都是很愚蠢的行为。
CCImage还有几个比较有趣的功能,他提供了一个saveToFile的函数。我们知道CCImage可以从相当多的格式初始化,那个这个saveToFile就可以作为一个转化函数来使用了。它能将图片保存为png或者jpg的格式,注意这个函数默认是不保存透明的,如果需要可以将其第二个参数设置为true。你可以采用压缩的图片格式打包,然后在游戏第一次运行的时候将其保存为易于解码的格式,来达到游戏发布体积和加载速度上的平衡。CCImage就能简单的完成这个操作。
CCImage还有一个功能就是,它能从一个string初始化一个图片。另外IOS和Android还提供了一个initWithStringShadowStroke的功能。如果你要显示很有艺术感的字体,不妨用用这个函数。字体的渲染向来都是很恶心的内容,在Windows和Android上cocos2d-x采用了一个叫做BitmapDC的概念,再调用各自的平台特性来完成这个工作。在Android上是采用jni的方式调用系统的函数实现的。在iOS上直接采用了系统函数,没有借用BitmapDC这个概念。有一个问题就是,如果你在Android上开启了Debug模式,那么会输出相当多的JVM释放资源的信息,这是因为每一次信息改动都生成了一张显示图片,造成JVM频繁回收。这极大的影响了游戏性能。所以TTF文件使用在Android上是极其低效的,如果你要做聊天,这方面有很大的优化余地。
相关文章推荐
- cocos2d-x 源码剖析(4)
- cocos2d-x 源码剖析(9)
- cocos2d-x源码剖析之场景管理
- cocos2d-x源码剖析引子
- cocos2d-x 源码剖析(5)
- cocos2d-x 源码剖析(10)
- cocos2d-x应用窗口相关源码剖析5-其他细节
- cocos2d-x 源码剖析(11)
- cocos2d-x源码剖析之精灵对象
- cocos2d-x 源码剖析(6)
- cocos2d-x 源码剖析(12)
- cocos2d-x 源码剖析(13)
- 【cocos2d-x 源码剖析】启动窗口
- cocos2d-x 源码剖析(14)
- cocos2d-x 源码剖析(16)
- cocos2d-x源码剖析之整体框架
- cocos2d-x应用窗口相关源码剖析1
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(15)----帧缓冲
- cocos2d-x 源码剖析(17)
- cocos2d-x应用窗口相关源码剖析2