1.所有文本框必须实现CCLabelProtocol接口 2.CCLableTTF比另外两个文本框渲染慢 TTF(TrueTypeFont)是一种字库名称,是Apple公司和Microsoft公司共同推出的字体文件式,随着windows的流行,已经变成最常用的一种字体文件表示方式。 CCLabelTTF 所以, 而应该
1.所有文本框必须实现CCLabelProtocol接口
2.CCLableTTF比另外两个文本框渲染慢
TTF(TrueTypeFont)是一种字库名称,是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。
CCLabelTTF所以,而应该使用CCLabelAtlas或者是CCLabelBMFont OK, 看下它的使用方法CCLabelTTF *label = CCLabelTTF::labelWithString("the string", "Marker Felt", 21);this->addChild(label);label->setPosition(ccp(100, 100));label->setString("change string");//修改文字的方法这个类使用的是系统中的字体,不需要额外往项目文件中添加字体文件。但如果你有自定义的字体也可以加到项目中,如果无法使用,可以查看一下ccConfig.h中的CC_FONT_LABEL_SUPPORT是否enable了。
3.CCLabelBMFont中每个文字相当于一个CCSprite,可以旋转,移动,改变尺寸等CCLabelBMFont相当于每次改变只改变了图片坐标,而CCLabelTTF要重新渲染.这个类使用之前,需要添加好字体文件,包括一个图片文件 (**.png) 和一个 字体坐标文件 (**.fnt)。
在 cocos2d-x的示例项目中有现成的,可以先拿过来练习一下,找的时候注意两个文件的名称是相同的,只是扩展名不同。
CCLabelIBMFont *label = CCLabelIBMFont::labelWithString("the string", "font-hd.png");this->addChild(label);label->setPosition(ccp(100, 100));label->setString("change string");下面是font-hd.png文件的截图font-hd.fnt文件定义了 图像文件的名称,以及每个字符对应的位置信息。
这个没办法指定字体的字号,但可以用scale属性进行缩放来调整大小。就当它是sprite,可以简单的实现很炫的文字的动画效果。
4.CCLabelAtlas
如果你用cocos2d-x项目模板创建过项目,那么你已经看过它的效果了,就是左下角显示帧率的数字。
因为帧率一直在变,使用CCLabelTTF的话效率太低,因为只是数字所以也犯不上使用 CCLabelBMFont 加载那么大的文字图像,所以使用这个比较合适。
CCLabelAtlas *label = CCLabelAtlas::labelWithString("12", "fps_images.png", 12, 18, ".");this->addChild(label);label->setPosition(ccp(100, 100));label->setString("34");在项目文件中,在resourse group里你可以找一下一个叫 fps_images.png的这个图像文件,文件如下:所以,这个只能显示上面这个12个字符,abcd什么的就不行了。
解释一下参数,12就是字符,fps_images.png就是字符的图像文件(这个只要图像文件就可以了),12是每个字符的宽度,18是每个字符的高度,这个不能设错,否则显示的时候可能就不对了。
最后一个是起始字符,它是使用这个其实字符来对应字符和图像关系的
5.下面具体分析一下画字的原理(参考一篇博客)
图字,顾名思义,利用图片做为纹理来显示的文字。当下流行的跨平台2D引擎Cocos2d-x和LibGdx也都有对于图字的应用支持,今天我就来为大家讲一讲图字。
首先要介绍一下,图字是怎么来的?其实这个很早很早了,记得80后在95年开始玩DOS下的仙剑奇侠传的时候,那些令人难忘的中文对话吧!DOS下做游戏,使用的是C语言,不要说写字了,很多复杂的操作甚至涉及驱动。那时候绘图就是利用将图片中的像素取出来后绘制在屏幕上,所以处理游戏中的中文,就只有把这些文字的像素预先写到BMP或二进制文件中,然后读取出来再设置屏幕像素以实现。后来进入DDRAW的时代,可以使用WINDOWS系统中的字库来写字了。把DDRAW的后台表面进行LOCK,取出其DC,然后用GDI将文字写到其DC上,这种做法后面也延续了很久,但GDI进行TextOut的效率非常慢,你要是想像梦幻西游一样满屏写了,那得卡死,解决方案是什么?还是图字。专业的游戏开发者会将所用到的字都预处理生成到一张图片中,通过一个编码与纹理UV对应文件来进行纹理UV的获取后做为顶点的UV值然后进行绘制,有也的在每一帧中实时的将需要的字使用DDRAW写字的方法绘制到相应的纹理上然后使用文字编码与纹理UV对应信息来进行绘制,这样效率就提高很多了。目前比较流行的做法是使用一张png图片来存储用到的文字。一个.fnt文件来存储文字图片说明信息。Cocos2d-x和LibGdx中都集成了相关的图字处理类。在世界范围内,也有很多游戏使用了这个方案。在游戏汉化界,了解和掌握图字的原理和修改方法也是很重要的一项工作我们以Cocos2d-x的tests工程中的LabelTest中的最后一个Label显示“中国”为例来分析一下。
打开Cocos2d-x所在目录下的tests\Resources\fonts目录,找到bitmapFontChinese.png(文字贴图文件)和bitmapFontChinese.fnt(文字图片说明信息文件)先打开png,我们可以看到它是512×512大小,上面由12行,14列个文字组成。包括有一些汉字,常用字符,数字和字母。它的每个字都是由青色到蓝色的向下渐变。
再用UEdit或记事本打开bitmapFontChinese.fnt,可以看到它的构成,我在这里讲一下。
第一行是对字体的介绍。
1info face="华康海报体W12(P)" size=32 bold=0italic=0 charset="" unicode=0stretchH=100smooth=1 aa=1 padding=0,0,0,0 spacing=1,1
解释:
face=”华康海报体W12(P)”:字体为”华康海报体W12(P)”,size=32:大小为32像素bold=0 :不加粗italic=0:不使用斜体charset=”":charset是编码字符集,这里没有填写值即使用默认,unicode=0:不使用Unicode stretchH=100:纵向缩放百分比smooth=1 :开启平滑aa=1:开启抗锯齿padding=0,0,0,0:内边距,文字与边框的空隙。
spacing=1,1 :外边距,就是相临边缘的距离。
第二行是对应所有字贴图的公共信息1common lineHeight=37 base=28 scaleW=512 scaleH=512pages=1 packed=0
解释:
lineHeight=37:行高,如果遇到换行符时,绘制字的位置坐标的Y值在换行后增加的像素值。
base=28 :字的基本大小scaleW=512 :图片大小scaleH=512:图片大小pages=1 :此种字体共用到几张图。
packed=0:图片不压缩第三行是对应当前字贴图的信息//第一页,文件名称是”bitmapFontChinese.png”
page id=0 file=”bitmapFontChinese.png”
第四行是当前贴图中所容纳的文字数量chars count=204第五行起把当前贴图中所用到的所有文字的编码以及对应在图片上的矩形位置,偏移等列出来第一个字符编码为32,也就是空格,位置为0,0,宽高为0,0, 绘制到屏幕的相应位置时,像素偏移(0,28),绘制完后相应位置的x往后移15像素再画下一个字符,字的图块在第1页上char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=28 xadvance=15 page=0 chnl=0第一个字符编码为汉字”象”,也就是空格,位置为0,0,宽为33,高为36, 绘制到屏幕的相应位置时,像素偏移(0,-1),绘制完后相应位置的x往后移36像素再画下一个字,字的图块在第1页上char id=35937 x=0 y=0 width=33 height=36 xoffset=0 yoffset=-1 xadvance=36 page=0 chnl=0 char id=26696 x=33 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0 char id=26071 x=68 y=0 width=35 height=36 xoffset=-1 yoffset=-1 xadvance=36 page=0 chnl=0…
再后面是描述两个字在进行组合绘制时字距调整的相关信息,这里没有要进行间距调整的字组合所以为设-1。对于字组合间距调整可以看此示例图:kernings count=-1这个数字代表参与字组合间距调整的字的数量。
如果kernings count大于零,后面会有类似这样的描述:kerning first=102 second=41 amount=2也就是’f’与’)’进行组合显示’f)’时,’)’向右移2像素防止粘在一起。
通过上面这些信息,引擎可以通过编码找到相应的文字并取出对应的纹理块。
//Cocos2d-x中LabelBMFontChinese下面我们来分析一下Cocos2d-x的tests工程中的LabelTest中的最后一个Label,它的类名为CCLabelBMFont.转到其类定义文件CCLabelBMFont.h 1classCC_DLL CCLabelBMFont:publicCCSpriteBatchNode,publicCCLabelProtocol,publicCCRGBAProtocol可以看到其直接派生于三个类,分别是CCSpriteBatchNode :精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。
CCLabelProtocol :文字字串类CCRGBAProtocol:颜色调节接口类由简入深,我们先来看一下CCRGBAProtocol,打开CCProtocols.h 123456789101112131415161718192021classCC_DLL CCRGBAProtocol{public://设置颜色virtualvoidsetColor(constccColor3B&color)=0;//取得颜色virtualconstccColor3B&getColor(void)=0;//返回透明度virtualGLubyte getOpacity(void)=0;//设置透明度virtualvoidsetOpacity(GLubyte opacity)=0;//设置是否使用Alpha值设置RGB,如果virtualvoidsetIsOpacityModifyRGB(boolbValue)=0;//取得是否使用Alpha值设置RGBvirtualboolgetIsOpacityModifyRGB(void)=0;};可以看到CCRGBAProtocol类是个纯虚类,只是定义了一些设置获取颜色信息的接口函数。
继续看CCLabelProtocal,明显的,它也是纯虚类,做为存储字符串的接口使用:123456789classCC_DLL CCLabelProtocol{public:virtualvoidsetString(constchar*label)=0;virtualconstchar*getString(void)=0;};最后来分析CCSpriteBatchNode类。它由CCNodet 和 CCTextureProtocal两个类派生而来,CCNode是基础结点类,用于将引擎中所有具有逻辑顺序和父子关系的类组织起来,基于CCNode派生的类均可以互相挂接。CCNode不是本章要详细介绍的内容,就不再详细分析了,看一下CCTextureProtocol,这是一个纹理使用接口类:123456789classCC_DLL CCTextureProtocol:publicCCBlendProtocol{public:// 返回所使用的2D纹理virtualCCTexture2D*getTexture(void)=0;// 设置使用的2D纹理,并为纹理的使用计数器加1操作virtualvoidsetTexture(CCTexture2D*texture)=0;};很简单,只有两个函数对纹理进行设置和获取,它派生于CCBlendProtocal,这是一个Alpha混合系数设置接口类,用于在开启Alpha混合状态后对Alpha混合的系数进行设置。再来看一下CCBlendProtocal,这是一个混合状态设置接口类:123456789classCC_DLL CCBlendProtocol{public:// 为纹理设置使用的混合状态virtualvoidsetBlendFunc(ccBlendFunc blendFunc)=0;// 返回为纹理设置的混合状态virtualccBlendFunc getBlendFunc(void)=0;};返回到类CCSpriteBatchNode的定义。我们再来分析CCSpriteBatchNode。之前说了CCSpriteBatchNode是精灵批次管理类,用于将使用一张图的多个精灵在设置一次纹理的批次里进行绘制,提高渲染的效率。既然多个精灵使用一张图,则需要将多个小图块合并在一张图上,这样只要设置使用大图做为纹理,将使用各小图块做为纹理贴图的精灵设置好顶点与UV等数据,就可以绘制出这些精灵了。Cocos2d-x提供了一个类CCTextureAtlas对使用图块的这些精灵所使用的顶点缓冲区进行管理。为了更好的理解CCSpriteBatchNode,我们看一下它的定义和实现:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586#ifndef __CCTEXTURE_ATLAS_H__#define __CCTEXTURE_ATLAS_H__//用到的头文件#include#include "ccTypes.h"#include "CCObject.h"#include "ccConfig.h"//使用Cocos2d命名空间namespacecocos2d{classCCTexture2D;//CCTextureAtlas由CCObject派生而来classCC_DLL CCTextureAtlas:publicCCObject{protected://使用此大图中的图块的精灵对应的三角形索引数组的指针GLushort*m_pIndices;#if CC_USES_VBO//如果使用Vertex Buffer Object(VBO:使用显存而非内存存储顶点缓冲数据,大大提高效率),建立VBO句柄数组,第一个元素存顶点数组的句柄,第二个元素存索引数组句柄GLuint m_pBuffersVBO[2];//标记是否更新需要更新的图块信息。当你新加入了图块或者修改了图块,需要设置为true。boolm_bDirty;#endif // CC_USES_VBO// CC_PROPERTY_READONLY宏为类定义变量及增加相应的get函数。//当前使用图块的数量CC_PROPERTY_READONLY(unsignedint, m_uTotalQuads, TotalQuads)//存储图块信息的数组容量CC_PROPERTY_READONLY(unsignedint, m_uCapacity, Capacity)//设置所使用的大图纹理CC_PROPERTY(CCTexture2D*, m_pTexture, Texture)//使用此大图的图块的所有精灵的顶点缓冲信息数组CC_PROPERTY(ccV3F_C4B_T2F_Quad*, m_pQuads, Quads)public://构造CCTextureAtlas();//析构virtual~CCTextureAtlas();//描述char*description();//静态函数:从文件中创建纹理,并初始化图块容量staticCCTextureAtlas*textureAtlasWithFile(constchar*file ,unsignedintcapacity);//同上,只是非静态函数。作者提示不能重复调用,否则会造成内存泄漏。boolinitWithFile(constchar*file,unsignedintcapacity);//静态函数:从贴图中创建纹理,并初始化图块容量staticCCTextureAtlas*textureAtlasWithTexture(CCTexture2D*texture,unsignedintcapacity);//同上,只是非静态函数。作者提示不能重复调用,否则会造成内存泄漏。boolinitWithTexture(CCTexture2D*texture,unsignedintcapacity);//通过索引值找到对应的图块顶点缓冲数据并用新数据修改它,由CCSprite实例对象在变换顶点信息时调用。voidupdateQuad(ccV3F_C4B_T2F_Quad*quad,unsignedintindex);//通过索引值找到对应的图块顶点缓冲数据,并在其之前插入一个新的图块。voidinsertQuad(ccV3F_C4B_T2F_Quad*quad,unsignedintindex);//通过索引值找到对应的图块顶点缓冲数据,并把它插入另一个图块之前。voidinsertQuadFromIndex(unsignedintfromIndex,unsignedintnewIndex);//移除指定位置的图块顶点缓冲数据.voidremoveQuadAtIndex(unsignedintindex);//清空所有的图块顶点缓冲数据。voidremoveAllQuads();//重新设置图块顶点缓冲数组的容量boolresizeCapacity(unsignedintn);//绘制指定的图块顶点缓冲voiddrawNumberOfQuads(unsignedintn);//绘制从指定的图块起后面的N个图块voiddrawNumberOfQuads(unsignedintn,unsignedintstart);//绘制所有的图块顶点缓冲voiddrawQuads();private://初始化索引缓冲数据voidinitIndices();};}//namespace cocos2d#endif //__CCTEXTURE_ATLAS_H__再看CPP:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471#include "CCTextureAtlas.h"#include "CCTextureCache.h"#include "ccMacros.h"// 纹理头文件#include "CCTexture2D.h"#include//使用Cocos2d命名空间namespacecocos2d{//构造,初始化成员变量CCTextureAtlas::CCTextureAtlas():m_pIndices(NULL)#if CC_USES_VBO, m_bDirty(false)#endif,m_pTexture(NULL),m_pQuads(NULL){}//析构,释放所用的内存CCTextureAtlas::~CCTextureAtlas(){// CCLOGINFO("cocos2d: deallocing CCTextureAtlas.");CC_SAFE_FREE(m_pQuads)CC_SAFE_FREE(m_pIndices)#if CC_USES_VBO//释放缓冲区对象glDeleteBuffers(2, m_pBuffersVBO);#endif // CC_USES_VBOCC_SAFE_RELEASE(m_pTexture);}//实现通过宏CC_PROPERTY_READONLY声明的函数//取得当前使用的图块的数量unsignedintCCTextureAtlas::getTotalQuads(){returnm_uTotalQuads;}//取得图块集的容量unsignedintCCTextureAtlas::getCapacity(){returnm_uCapacity;}//取得大纹理CCTexture2D*CCTextureAtlas::getTexture(){returnm_pTexture;}//设置大纹理voidCCTextureAtlas::setTexture(CCTexture2D*var){CC_SAFE_RETAIN(var);CC_SAFE_RELEASE(m_pTexture);m_pTexture=var;}//取得使用此大图的图块的所有精灵的顶点缓冲信息数组ccV3F_C4B_T2F_Quad*CCTextureAtlas::getQuads(){returnm_pQuads;}//设置使用此大图的图块的所有精灵的顶点缓冲信息数组voidCCTextureAtlas::setQuads(ccV3F_C4B_T2F_Quad*var){m_pQuads=var;}//静态函数:从文件中创建纹理,并初始化图块容量CCTextureAtlas*CCTextureAtlas::textureAtlasWithFile(constchar*file,unsignedintcapacity){//使用new来实例化一个CCTextureAtlas对象CCTextureAtlas*pTextureAtlas=newCCTextureAtlas();//调用成员函数进行初始化if(pTextureAtlas&&pTextureAtlas->initWithFile(file, capacity)){pTextureAtlas->autorelease();returnpTextureAtlas;}//如果失败,释放后返回NULLCC_SAFE_DELETE(pTextureAtlas);returnNULL;}//静态函数:从贴图中创建纹理,并初始化图块容量CCTextureAtlas*CCTextureAtlas::textureAtlasWithTexture(CCTexture2D*texture,unsignedintcapacity){//使用new来实例化一个CCTextureAtlas对象CCTextureAtlas*pTextureAtlas=newCCTextureAtlas();//调用成员函数进行初始化if(pTextureAtlas&&pTextureAtlas->initWithTexture(texture, capacity)){pTextureAtlas->autorelease();returnpTextureAtlas;}//如果失败,释放后返回NULLCC_SAFE_DELETE(pTextureAtlas);returnNULL;}//非静态函数,从文件中创建纹理,并初始化图块容量boolCCTextureAtlas::initWithFile(constchar*file,unsignedintcapacity){// 由纹理管理器加载一个图片文件,返回生成的纹理CCTexture2D*texture=CCTextureCache::sharedTextureCache()->addImage(file);//判断生成纹理是否有效if(texture){//如果成功,使用纹理进行初始化returninitWithTexture(texture, capacity);}else{//不成功打印错误日志并返回NULLCCLOG("cocos2d: Could not open file: %s", file);deletethis;returnNULL;}}//非静态函数,设置纹理,并初始化图块容量boolCCTextureAtlas::initWithTexture(CCTexture2D*texture,unsignedintcapacity){//纹理有效性判断,防止重复调用CCAssert(texture!=NULL,"texture should not be null");//设置图块容量m_uCapacity=capacity;m_uTotalQuads=0;// 设置纹理this->m_pTexture=texture;CC_SAFE_RETAIN(m_pTexture);// 判断是否重复调用CCAssert(m_pQuads==NULL&&m_pIndices==NULL,"");//申请容量大小的的顶点缓冲信息数组m_pQuads=(ccV3F_C4B_T2F_Quad*)calloc(sizeof(ccV3F_C4B_T2F_Quad)*m_uCapacity,1);//申请容量大小的索引缓冲数组m_pIndices=(GLushort*)calloc(sizeof(GLushort)*m_uCapacity*6,1);//如果失败,做相应处理if(!(m_pQuads&&m_pIndices)&&m_uCapacity>0){//CCLOG("cocos2d: CCTextureAtlas: not enough memory");CC_SAFE_FREE(m_pQuads)CC_SAFE_FREE(m_pIndices)CC_SAFE_RELEASE_NULL(m_pTexture);returnfalse;}//初始化缓冲区对象#if CC_USES_VBOglGenBuffers(2,&m_pBuffersVBO[0]);m_bDirty=true;#endif // CC_USES_VBO//初始化索引缓冲this->initIndices();returntrue;}//取得描述char*CCTextureAtlas::description(){char*ret=newchar[100];sprintf(ret,"", m_uTotalQuads);returnret;}//初始化索引缓冲voidCCTextureAtlas::initIndices(){//如果容量为0直接返回if(m_uCapacity==0)return;//按照顶点的顺序和使用的三角形渲染排列方式为索引缓冲填充数据。for(unsignedinti=0;im_uCapacity;i++){#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIPm_pIndices[i*6+0]=i*4+0;m_pIndices[i*6+1]=i*4+0;m_pIndices[i*6+2]=i*4+2;m_pIndices[i*6+3]=i*4+1;m_pIndices[i*6+4]=i*4+3;m_pIndices[i*6+5]=i*4+3;#elsem_pIndices[i*6+0]=(GLushort)(i*4+0);m_pIndices[i*6+1]=(GLushort)(i*4+1);m_pIndices[i*6+2]=(GLushort)(i*4+2);// inverted index. issue #179m_pIndices[i*6+3]=(GLushort)(i*4+3);m_pIndices[i*6+4]=(GLushort)(i*4+2);m_pIndices[i*6+5]=(GLushort)(i*4+1);// m_pIndices[i*6+3] = i*4+2;// m_pIndices[i*6+4] = i*4+3;// m_pIndices[i*6+5] = i*4+1;#endif}#if CC_USES_VBO//指定m_pBuffersVBO[0]为顶点缓冲区,并激活缓冲区glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);//绑定完成后为其分配内存glBufferData(GL_ARRAY_BUFFER,sizeof(m_pQuads[0])*m_uCapacity, m_pQuads, GL_DYNAMIC_DRAW);//指定m_pBuffersVBO[1]为索引缓冲区,并激活缓冲区glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);//绑定完成后为其分配内存glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(m_pIndices[0])*m_uCapacity*6, m_pIndices, GL_STATIC_DRAW);//取消绑定glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);#endif // CC_USES_VBO}//通过索引值找到对应图块的顶点缓冲并用新数据修改它voidCCTextureAtlas::updateQuad(ccV3F_C4B_T2F_Quad*quad,unsignedintindex){//有效性判断CCAssert(index>=0&&indexm_uCapacity,"updateQuadWithTexture: Invalid index");//如果index大于现有的数量则更新数量m_uTotalQuads=max(index+1, m_uTotalQuads);//修改对应的数据值m_pQuads[index]=*quad;//需要更新#if CC_USES_VBOm_bDirty=true;#endif}//通过索引值找到对应图块的顶点缓冲,并在其位置之前插入一个新的图块。voidCCTextureAtlas::insertQuad(ccV3F_C4B_T2F_Quad*quad,unsignedintindex){//有效性判断CCAssert(indexm_uCapacity,"insertQuadWithTexture: Invalid index");//数量增加m_uTotalQuads++;CCAssert(m_uTotalQuadsm_uCapacity,"invalid totalQuads");//先将索引位置之后的数据整体后移一个位置,再用新数据填充索引位置的数据。实现插入操作。unsignedintremaining=(m_uTotalQuads-1)-index;if(remaining>0){// texture coordinatesmemmove(&m_pQuads[index+1],&m_pQuads[index],sizeof(m_pQuads[0])*remaining);}m_pQuads[index]=*quad;//设置需要更新m_pBuffersVBO中的VBO数组数据。#if CC_USES_VBOm_bDirty=true;#endif}//通过索引值找到对应图块的顶点缓冲,并把它插入另一个图块之前。voidCCTextureAtlas::insertQuadFromIndex(unsignedintoldIndex,unsignedintnewIndex){//有效性判断CCAssert(newIndex>=0&&newIndexm_uTotalQuads,"insertQuadFromIndex:atIndex: Invalid index");CCAssert(oldIndex>=0&&oldIndexm_uTotalQuads,"insertQuadFromIndex:atIndex: Invalid index");//两个索引相同直接返回即可if(oldIndex==newIndex)return;//计算要移动的图块数量unsignedinthowMany=(oldIndex-newIndex)>0?(oldIndex-newIndex):(newIndex-oldIndex);unsignedintdst=oldIndex;unsignedintsrc=oldIndex+1;if(oldIndex>newIndex){dst=newIndex+1;src=newIndex;}// 开始进行移动ccV3F_C4B_T2F_Quad quadsBackup=m_pQuads[oldIndex];memmove(&m_pQuads[dst],&m_pQuads[src],sizeof(m_pQuads[0])*howMany);//更新新索引位置的数据m_pQuads[newIndex]=quadsBackup;//设置需要更新m_pBuffersVBO中的VBO数组数据。#if CC_USES_VBOm_bDirty=true;#endif}//移除指定位置的图块顶点缓冲voidCCTextureAtlas::removeQuadAtIndex(unsignedintindex){//有效性判断CCAssert(indexm_uTotalQuads,"removeQuadAtIndex: Invalid index");unsignedintremaining=(m_uTotalQuads-1)-index;//将索引图块后的所有图块向前移1个位置即可// last object doesn't need to be movedif(remaining){// texture coordinatesmemmove(&m_pQuads[index],&m_pQuads[index+1],sizeof(m_pQuads[0])*remaining);}//数量减1m_uTotalQuads--;//设置需要更新m_pBuffersVBO中的VBO数组数据。#if CC_USES_VBOm_bDirty=true;#endif}//移除所有的顶点缓冲数据voidCCTextureAtlas::removeAllQuads(){//数量直接置0,这是最快的方式m_uTotalQuads=0;}// 重新设置图块顶点缓冲数组的容量boolCCTextureAtlas::resizeCapacity(unsignedintnewCapacity){//如果等于原来的容量直接返回if(newCapacity==m_uCapacity)returntrue;//确保当前绘制的精灵数量最大不能超过容量m_uTotalQuads=min(m_uTotalQuads, newCapacity);//更新容量m_uCapacity=newCapacity;//定义指针存放要申请的图块信息与索引数组的内存地址void*tmpQuads=NULL;void*tmpIndices=NULL;//为图块的顶点缓冲数组申请内存,注意:如果已占有内存则直接在原内存地址上进行内存长度调整if(m_pQuads==NULL)tmpQuads=calloc(sizeof(m_pQuads[0])*m_uCapacity,1);elsetmpQuads=realloc(m_pQuads,sizeof(m_pQuads[0])*m_uCapacity);//为图块的索引缓冲数组申请内存, 如果已占有内存则直接在原内存地址上进行内存长度调整if(m_pIndices==NULL)tmpIndices=calloc(sizeof(m_pIndices[0])*m_uCapacity*6,1);elsetmpIndices=realloc(m_pIndices,sizeof(m_pIndices[0])*m_uCapacity*6);//如果内存申请失败的处理if(!(tmpQuads&&tmpIndices)){//CCLOG("cocos2d: CCTextureAtlas: not enough memory");if(tmpQuads)free(tmpQuads);elsefree(m_pQuads);if(tmpIndices)free(tmpIndices);elsefree(m_pIndices);m_pQuads=NULL;m_pIndices=NULL;m_uCapacity=m_uTotalQuads=0;returnfalse;}//如果成功,则将内存地址赋给相应成员指针变量m_pQuads=(ccV3F_C4B_T2F_Quad*)tmpQuads;m_pIndices=(GLushort*)tmpIndices;//释放顶点缓冲对象并重新创建和进行绑定#if CC_USES_VBOglDeleteBuffers(2, m_pBuffersVBO);// initial bindingglGenBuffers(2,&m_pBuffersVBO[0]);m_bDirty=true;#endif // CC_USES_VBO//初始化索引缓冲this->initIndices();//设置需要更新m_pBuffersVBO中的VBO数组数据。上面已经设了,这里重复可以不要。#if CC_USES_VBOm_bDirty=true;#endifreturntrue;}//绘制所有的图块顶点缓冲数据voidCCTextureAtlas::drawQuads(){this->drawNumberOfQuads(m_uTotalQuads,0);}//绘制指定的图块顶点缓冲数据voidCCTextureAtlas::drawNumberOfQuads(unsignedintn){this->drawNumberOfQuads(n,0);}//绘制从指定的图块顶点缓冲数据起后面的N个图块顶点缓冲数据voidCCTextureAtlas::drawNumberOfQuads(unsignedintn,unsignedintstart){// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY// Unneeded states: -// 如果数量为零直接返回。if(0==n)return;//设置使用纹理glBindTexture(GL_TEXTURE_2D, m_pTexture->getName());#define kQuadSize sizeof(m_pQuads[0].bl)//如果使用VBO所进行的渲染设置#if CC_USES_VBO//指定m_pBuffersVBO[0]为顶点缓冲区,并激活缓冲区glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);//绑定完成后为其分配内存#if CC_ENABLE_CACHE_TEXTTURE_DATAglBufferData(GL_ARRAY_BUFFER,sizeof(m_pQuads[0
