我们来看一下cocos2d-x中的libcocos2d库,其下有许多目录,找到textures展开,可以看到有CCTexture2D,CCTextureAtlas,CCTextureCache,CCTexturePVR四个类。
这四个类的功能分别是:
CCTexture2D: 纹理,即图片加载入内存后供CPU和GPU操作的贴图对象。
CCTexturePVR:处理PVR文件生成纹理的类,提示:大家可以用它解析愤怒的小鸟中的图片。
CCTextureCache:纹理管理器,负责加载图片并对生成的纹理进行管理。通过“字典”来进行快速的查询。
CCTextureAtlas:纹理块管理器,如果图片是由多个小图块组成的,则纹理块管理器用来存储这些小图块的相关信息,以方便绘制相应图块。
为了让大家更好的学习纹理,在讲解纹理的代码之前我已经先给大家分析了本章用到的两个功能类:
CCImage和CCDictionary。这两个类分别在纹理模块中担任加载图片和管理纹理指针的作用。希望大家先顶一下这两篇贴子之后再开始下面的代码学习,你一定会感到非常容易。
一.CCTexture2D:
好,咱们现在开始看CCTexture2D:
- #ifndef__CCTEXTURE2D_H__
- #define__CCTEXTURE2D_H__
- #include<string>
- #include"cocoa/CCObject.h"
- #include"cocoa/CCGeometry.h"
- #include"ccTypes.h"
- //Cocos2d命名空间
- NS_CC_BEGIN
- //需要用到CCImage,这里声明一下。
- classCCImage;
- //纹理格式:即每个纹理中的像素单位分别是怎么为颜色值进行实际内存分配的。这个非常重要,我们在进行游戏开发的过程中,会常常与各种图片类型打交通。每种图片往往也有各自的像素格式。但当它们一旦加载到游戏中后,就会根据我们的要求变成以下某种类型的纹理。不同的纹理格式所占据的内存大小可能不同,我们要根据实际情况和需求来选择相应的纹理格式。比如我们用RGBA8888纹理格式来创建纹理,它占据的内存容量很大,如果我们要显示的纹理中没有ALPHA值,那就不应该使用带ALPHA通道的纹理格式。我们就可以改成RGB565像素格式。
- typedefenum{
- //32位真彩色,最真但最耗内存
- kCCTexture2DPixelFormat_RGBA8888,
- //24位真彩色,去掉了ALPHA通道
- kCCTexture2DPixelFormat_RGB888,
- //16位色,将RGB压缩在一个字中。绿色多了1位,因为人眼对绿色更敏感。
- kCCTexture2DPixelFormat_RGB565,
- //8位色,只存ALPHA值,做遮罩图用
- kCCTexture2DPixelFormat_A8,
- //8位色,只存灰度或者强度值,做灰度图用
- kCCTexture2DPixelFormat_I8,
- //16位色,只存ALPHA值与强度值,双功能
- kCCTexture2DPixelFormat_AI88,
- //16位色,RGBA四通道各占4位。
- kCCTexture2DPixelFormat_RGBA4444,
- //16位色,RGB三通道各占5位,多1位留做ALPHA镂空使用
- kCCTexture2DPixelFormat_RGB5A1,
- //PVR的PVRTC4压缩格式
- kCCTexture2DPixelFormat_PVRTC4,
- //PVRTC的PVRTC2压缩格式
- kCCTexture2DPixelFormat_PVRTC2,
- //默认格式RGBA8888
- kCCTexture2DPixelFormat_Default=kCCTexture2DPixelFormat_RGBA8888,
- //为了兼容性而保留的枚举值
- kTexture2DPixelFormat_RGBA8888=kCCTexture2DPixelFormat_RGBA8888,
- kTexture2DPixelFormat_RGB888=kCCTexture2DPixelFormat_RGB888,
- kTexture2DPixelFormat_RGB565=kCCTexture2DPixelFormat_RGB565,
- kTexture2DPixelFormat_A8=kCCTexture2DPixelFormat_A8,
- kTexture2DPixelFormat_RGBA4444=kCCTexture2DPixelFormat_RGBA4444,
- kTexture2DPixelFormat_RGB5A1=kCCTexture2DPixelFormat_RGB5A1,
- kTexture2DPixelFormat_Default=kCCTexture2DPixelFormat_Default
- }CCTexture2DPixelFormat;
- //需要使用Shader代码片段,这里声明一下
- classCCGLProgram;
- //定义了纹理的一些参数
- typedefstruct_ccTexParams{
- GLuintminFilter;//纹理过滤器:缩小过滤器
- GLuintmagFilter;//纹理过滤器:放大过滤器
- GLuintwrapS;//横向纹理寻址模式
- GLuintwrapT;//纵向纹理寻址模式
- }ccTexParams;
- //CCTexture2D类可以方便的从图片,文本或raw数据文件中创建OpenGL所用贴图,创建的贴图会自动转为2的幂次方大小,所以要注意对于贴图坐标的影响。
- classCC_DLLCCTexture2D:publicCCObject
- {
- public:
- //构造
- CCTexture2D();
- //析构
- virtual~CCTexture2D();
- //取得纹理的描述
- constchar*description(void);
- //释放数据
- voidreleaseData(void*data);
- //保存数据
- void*keepData(void*data,unsignedintlength);
- //由数据指针和指定的像素格式,图片宽高,来生成OpenGL贴图。
- boolinitWithData(constvoid*data,CCTexture2DPixelFormatpixelFormat,unsignedintpixelsWide,unsignedintpixelsHigh,constCCSize&contentSize);
- //在指定的位置绘制贴图
- voiddrawAtPoint(constCCPoint&point);
- //纹制贴图上的一个图像块
- voiddrawInRect(constCCRect&rect);
- //由CCImage指针生成OpenGL贴图
- boolinitWithImage(CCImage*uiImage);
- //由一个字符串生成OpenGL贴图。
- boolinitWithString(constchar*text,constCCSize&dimensions,CCTextAlignmenthAlignment,CCVerticalTextAlignmentvAlignment,constchar*fontName,floatfontSize);
- //由一个字符串和指定的字体与大小生成OpenGL贴图
- boolinitWithString(constchar*text,floatfontSize);
- //如果支持PVR的压缩格式
- #ifdefCC_SUPPORT_PVRTC
- //由一个PVR压缩格式的数据生成OpenGL贴图
- boolinitWithPVRTCData(constvoid*data,intlevel,intbpp,boolhasAlpha,intlength,CCTexture2DPixelFormatpixelFormat);
- #endif//CC_SUPPORT_PVRTC
- //从普通PVR文件生成OpenGL贴图
- boolinitWithPVRFile(constchar*file);
- //设置贴图参数
- voidsetTexParameters(ccTexParams*texParams);
- //设置为抗锯齿的贴图过滤方式(线性过滤)
- voidsetAntiAliasTexParameters();
- //设置为非抗锯齿的贴图过滤方式(最近点采样)
- voidsetAliasTexParameters();
- //生成多级贴图:由图片数据生成一系列尺寸为2的幂次方直至当前贴图大小的贴图。系统会根据距离自动选择纹理图片。可以解决大图片显示在小空间时的闪烁问题。
- voidgenerateMipmap();
- //取得像素格式名称
- constchar*stringForFormat();
- //返回当前贴图色深,即每个像素占多少位
- unsignedintbitsPerPixelForFormat();
- //通过参数贴图格式返回纹理色深
- unsignedintbitsPerPixelForFormat(CCTexture2DPixelFormatformat);
- //静态函数,用于设置默认带ALPHA通道的贴图像素格式。则图片创建为贴图时,如果有ALPHA通道,则生成此默认贴图像素格式。
- staticvoidsetDefaultAlphaPixelFormat(CCTexture2DPixelFormatformat);
- //静态函数,取得默认带ALPHA通道的贴图像素格式。
- staticCCTexture2DPixelFormatdefaultAlphaPixelFormat();
- //静态函数,设置载入PVR时是否开启ALPHA渐变,默认不开启,则ALPHA值只有是与否,无渐变。
- staticvoidPVRImagesHavePremultipliedAlpha(boolhaveAlphaPremultiplied);
- //取得图片大小(以像素为单位)
- constCCSize&getContentSizeInPixels();
- //是否有ALPHA渐变值
- boolhasPremultipliedAlpha();
- //是否有多级贴图
- boolhasMipmaps();
- private:
- //加载一个带ALPHA渐变的图片生成OpenGL贴图
- boolinitPremultipliedATextureWithImage(CCImage*image,unsignedintpixelsHigh);
- //ALPHA渐变开关
- boolm_bPVRHaveAlphaPremultiplied;
- //贴图格式变量及get接口
- CC_PROPERTY_READONLY(CCTexture2DPixelFormat,m_ePixelFormat,PixelFormat)
- //贴图宽度及get接口
- CC_PROPERTY_READONLY(unsignedint,m_uPixelsWide,PixelsWide)
- //贴图高度及get接口
- CC_PROPERTY_READONLY(unsignedint,m_uPixelsHigh,PixelsHigh)
- //OpenGL贴图索引及get接口
- CC_PROPERTY_READONLY(GLuint,m_uName,Name)
- //横向贴图坐标终点。因为图片如果不是2的幂次方,图片大小会小于贴图的大小,贴图一定是2的幂次方嘛,这时候横向的贴图坐标终点不是1.0。
- CC_PROPERTY(GLfloat,m_fMaxS,MaxS)
- //纵向贴图坐标终点。
- CC_PROPERTY(GLfloat,m_fMaxT,MaxT)
- //图片大小及get接口
- CC_PROPERTY_READONLY(CCSize,m_tContentSize,ContentSize)
- //ALPHA渐变开关
- boolm_bHasPremultipliedAlpha;
- //多级纹理开关
- boolm_bHasMipmaps;
- //Shader代码片段指针
- CC_PROPERTY(CCGLProgram*,m_pShaderProgram,ShaderProgram);
- };
- NS_CC_END
- #endif//__CCTEXTURE2D_H__
再来看CCTexture2D.cpp:
- #include"CCTexture2D.h"
- #include"ccConfig.h"
- #include"ccMacros.h"
- #include"CCConfiguration.h"
- #include"platform/platform.h"
- #include"platform/CCImage.h"
- #include"CCGL.h"
- #include"support/ccUtils.h"
- #include"platform/CCPlatformMacros.h"
- #include"textures/CCTexturePVR.h"
- #include"CCDirector.h"
- #include"shaders/CCGLProgram.h"
- #include"shaders/ccGLStateCache.h"
- #include"shaders/CCShaderCache.h"
- //这里定义是否使用可变纹理
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- #include"CCTextureCache.h"
- #endif
- //Cocos2d-x命名空间
- NS_CC_BEGIN
- //静态全局的默认贴图像素格式。缺省为kCCTexture2DPixelFormat_Default,即RGBA8888。
- staticCCTexture2DPixelFormatg_defaultAlphaPixelFormat=kCCTexture2DPixelFormat_Default;
- //静态全局的PVR是否有ALPHA渐变的开关变量,默认为否。
- staticboolPVRHaveAlphaPremultiplied_=false;
- //构造函数。
- CCTexture2D::CCTexture2D()
- :m_uPixelsWide(0)
- ,m_uPixelsHigh(0)
- ,m_uName(0)
- ,m_fMaxS(0.0)
- ,m_fMaxT(0.0)
- ,m_bHasPremultipliedAlpha(false)
- ,m_bHasMipmaps(false)
- ,m_bPVRHaveAlphaPremultiplied(true)
- ,m_pShaderProgram(NULL)
- {
- }
- //析构
- CCTexture2D::~CCTexture2D()
- {
- //如果使用可变纹理,删除此可变纹理中的数据。
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- VolatileTexture::removeTexture(this);
- #endif
- //打印日志。
- CCLOGINFO("cocos2d:deallocingCCTexture2D%u.",m_uName);
- //释放所用到的Shader代码片段
- CC_SAFE_RELEASE(m_pShaderProgram);
- //释放OpenGL所用到的贴图。
- if(m_uName)
- {
- ccGLDeleteTexture(m_uName);
- }
- }
- //取得当前纹理的贴图像素格式。
- CCTexture2DPixelFormatCCTexture2D::getPixelFormat()
- {
- returnm_ePixelFormat;
- }
- //取得贴图宽度。
- unsignedintCCTexture2D::getPixelsWide()
- {
- returnm_uPixelsWide;
- }
- //取得贴图高度。
- unsignedintCCTexture2D::getPixelsHigh()
- {
- returnm_uPixelsHigh;
- }
- //取得贴图索引。
- GLuintCCTexture2D::getName()
- {
- returnm_uName;
- }
- //取得图片大小(以点为单位)
- CCSizeCCTexture2D::getContentSize()
- {
- //CC_CONTENT_SCALE_FACTOR宏返回的是在不同屏幕下的点与像素的比率。Mac电脑上返回1.而使用Retina显示屏的iphone上返回2。
- CCSizeret;
- ret.width=m_tContentSize.width/CC_CONTENT_SCALE_FACTOR();
- ret.height=m_tContentSize.height/CC_CONTENT_SCALE_FACTOR();
- returnret;
- }
- //取得图片大小(以像素为单位)
- constCCSize&CCTexture2D::getContentSizeInPixels()
- {
- returnm_tContentSize;
- }
- //取得横向的贴图坐标终点
- GLfloatCCTexture2D::getMaxS()
- {
- returnm_fMaxS;
- }
- //设置横向的贴图坐标终点
- voidCCTexture2D::setMaxS(GLfloatmaxS)
- {
- m_fMaxS=maxS;
- }
- //取得纵向的贴图坐标终点
- GLfloatCCTexture2D::getMaxT()
- {
- returnm_fMaxT;
- }
- //设置纵向的贴图坐标终点
- voidCCTexture2D::setMaxT(GLfloatmaxT)
- {
- m_fMaxT=maxT;
- }
- //所用到的Shader代码片段。
- CCGLProgram*CCTexture2D::getShaderProgram(void)
- {
- returnm_pShaderProgram;
- }
- //设置用到的Shader代码片段。
- voidCCTexture2D::setShaderProgram(CCGLProgram*pShaderProgram)
- {
- CC_SAFE_RETAIN(pShaderProgram);
- CC_SAFE_RELEASE(m_pShaderProgram);
- m_pShaderProgram=pShaderProgram;
- }
- //释放数据
- voidCCTexture2D::releaseData(void*data)
- {
- free(data);
- }
- //保存数据
- void*CCTexture2D::keepData(void*data,unsignedintlength)
- {
- //这里只是使用CC_UNUSED_PARAM宏用一下length,没什么实际功能。作者给出这个函数是预备未来供子类重载。
- CC_UNUSED_PARAM(length);
- returndata;
- }
- //是否有ALPHA渐变的通道数据。
- boolCCTexture2D::hasPremultipliedAlpha()
- {
- returnm_bHasPremultipliedAlpha;
- }
- //由数据指针创建指定大小和格式的贴图。取得创建成功后图片在贴图中的实际区域。
- boolCCTexture2D::initWithData(constvoid*data,constCCSize&contentSize)
- {
- //如果是RGBA8888格式或者大小正好就是2的幂次方。像素数据按四字节(DWORD)对齐。否则按1字节(BYTE)进行对齐。
- if(pixelFormat==kCCTexture2DPixelFormat_RGBA8888||(ccNextPOT(pixelsWide)==pixelsWide&&ccNextPOT(pixelsHigh)==pixelsHigh))
- {
- glPixelStorei(GL_UNPACK_ALIGNMENT,4);
- }
- else
- {
- glPixelStorei(GL_UNPACK_ALIGNMENT,1);
- }
- //产生一个OpenGL的贴图索引。
- glGenTextures(1,&m_uName);
- //将此贴图绑定为GL_TEXTURE_2D纹理。
- ccGLBindTexture2D(m_uName);
- //设置OpenGL中的贴图的过滤参数。
- 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);
- //这里根据不同的像素格式来生成不同的OpenGL所用的贴图。注意:传入的宽和高在成功生成贴图后会返回实际贴图的宽和高。如果图片不是2的幂次方,这个数值会改成2的幂次方。比如你传入的图片宽高是148x245,则调用完成后宽高会转成256x256。
- switch(pixelFormat)
- {
- casekCCTexture2DPixelFormat_RGBA8888:
- glTexImage2D(GL_TEXTURE_2D,GL_RGBA,(GLsizei)pixelsWide,(GLsizei)pixelsHigh,GL_UNSIGNED_BYTE,data);
- break;
- casekCCTexture2DPixelFormat_RGB888:
- glTexImage2D(GL_TEXTURE_2D,GL_RGB,data);
- break;
- casekCCTexture2DPixelFormat_RGBA4444:
- glTexImage2D(GL_TEXTURE_2D,GL_UNSIGNED_SHORT_4_4_4_4,data);
- break;
- casekCCTexture2DPixelFormat_RGB5A1:
- glTexImage2D(GL_TEXTURE_2D,GL_UNSIGNED_SHORT_5_5_5_1,data);
- break;
- casekCCTexture2DPixelFormat_RGB565:
- glTexImage2D(GL_TEXTURE_2D,GL_UNSIGNED_SHORT_5_6_5,data);
- break;
- casekCCTexture2DPixelFormat_AI88:
- glTexImage2D(GL_TEXTURE_2D,GL_LUMINANCE_ALPHA,data);
- break;
- casekCCTexture2DPixelFormat_A8:
- glTexImage2D(GL_TEXTURE_2D,GL_ALPHA,data);
- break;
- casekCCTexture2DPixelFormat_I8:
- glTexImage2D(GL_TEXTURE_2D,GL_LUMINANCE,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);
- //默认不使用ALPHA渐变通道。
- m_bHasPremultipliedAlpha=false;
- //默认不使用多级纹理。
- m_bHasMipmaps=false;
- //设置使用kCCShader_PositionTexture对应类型的Shader。此Shader的顶点格式由位置和纹理坐标组成。
- setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture));
- returntrue;
- }
- //取得纹理的描述
- constchar*CCTexture2D::description(void)
- {
- returnCCString::createWithFormat("<CCTexture2D|Name=%u|Dimensions=%ux%u|Coordinates=(%.2f,%.2f)>",m_fMaxT)->getCString();
- }
- //由CCImage对象来初始化纹理生成OpenGL贴图。
- boolCCTexture2D::initWithImage(CCImage*uiImage)
- {
- //参数有效性判断。
- if(uiImage==NULL)
- {
- CCLOG("cocos2d:CCTexture2D.Can'tcreateTexture.UIImageisnil");
- this->release();
- returnfalse;
- }
- //取得图片的宽高
- unsignedintimageWidth=uiImage->getWidth();
- unsignedintimageHeight=uiImage->getHeight();
- //取得引擎的配置信息
- CCConfiguration*conf=CCConfiguration::sharedConfiguration();
- //取得配置信息中指定的最大纹理大小
- unsignedmaxTextureSize=conf->getMaxTextureSize();
- //如果当前图片大于指定的最大纹理大小,提示错误警告交释放当前纹理返回NULL。
- if(imageWidth>maxTextureSize||imageHeight>maxTextureSize)
- {
- CCLOG("cocos2d:WARNING:Image(%ux%u)isbiggerthanthesupported%ux%u",imageWidth,imageHeight,maxTextureSize,maxTextureSize);
- this->release();
- returnNULL;
- }
- //总是按加载ALPHA渐变的图片方式来生成OpenGL贴图
- returninitPremultipliedATextureWithImage(uiImage,imageHeight);
- }
- //加载一个带ALPHA渐变的图片生成OpenGL贴图
- boolCCTexture2D::initPremultipliedATextureWithImage(CCImage*image,unsignedintwidth,unsignedintheight)
- {
- //取得图片的相关信息
- //定义指针变量指向图片像素数据。
- unsignedchar*tempData=image->getData();
- //定义无符号int指针变量,也是为了指向32位色深的图片像素数据,以便使指针直接对应指定的一个像素数据位置。
- unsignedint*inPixel32=NULL;
- //定义无符号char指针变量,也是为了指向8位色深的图片像素数据,以便使指针直接对应指定的一个像素数据位置。
- unsignedchar*inPixel8=NULL;
- //定义无符号short指针变量,指向16位色深的贴图像素数据,以便使指针直接对应指定的一个像素数据位置。
- unsignedshort*outPixel16=NULL;
- //定义bool变量hasAlpha取得图片是否有Alpha通道。
- boolhasAlpha=image->hasAlpha();
- //定义变量imageSize保存图片大小。
- CCSizeimageSize=CCSizeMake((float)(image->getWidth()),(float)(image->getHeight()));
- //定义变量pixelFormat用来保存贴图的像素格式。
- CCTexture2DPixelFormatpixelFormat;
- //定义变量bpp保存图片的色深。
- size_tbpp=image->getBitsPerComponent();
- //如果有ALPHA通道,使用默认的RGBA8888格式。
- if(hasAlpha)
- {
- pixelFormat=g_defaultAlphaPixelFormat;
- }
- else
- {//如果没有ALPHA通道
- //如果色深大于等于8,则转为RGB888格式,否则转为RGB565格式。这里有点问题,感觉应该按色深大于16来进行判断。即24和32位都转为RGB888,而16位及以下转为RGB565。
- if(bpp>=8)
- {
- pixelFormat=kCCTexture2DPixelFormat_RGB888;
- }
- else
- {
- pixelFormat=kCCTexture2DPixelFormat_RGB565;
- }
- }
- //取得数据的长度
- unsignedintlength=width*height;
- //根据图片的不同格式和要创建的纹理格式,将数据填充到纹理中。
- if(pixelFormat==kCCTexture2DPixelFormat_RGB565)
- {
- //根据是否有ALPHA通道来分别进行填充处理
- if(hasAlpha)
- {
- //转换RGBA8888到RGB565
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRRGGGGGGBBBBB"
- //一个像素占2个字节,所以图像中所有像素占用的字节数为width*height*2。由此大小申请内存作为贴图的像素数据。
- tempData=newunsignedchar[width*height*2];
- //将贴图像素数据的地址返回给unsignedshort指针。这样outPixel16就指向了贴图中的第一个像素的数据位置。
- outPixel16=(unsignedshort*)tempData;
- //因为有alpha,则图片是32位RGBA8888格式。取得图像的像素数据地址返回给unsignedint指针,则inPixel32指向了贴图中第一个像素的数据位置。
- inPixel32=(unsignedint*)image->getData();
- //遍历图片中所有的像素,逐像素处理。
- for(unsignedinti=0;i<length;++i,++inPixel32)
- {//将inPixel32指向的unsignedint数据通过取出R,G,B各8位数据值,然后组成RGB565值。放入outPixel16指向的unsignedshort数据中。
- *outPixel16++=
- ((((*inPixel32>>0)&0xFF)>>3)<<11)|//R
- ((((*inPixel32>>8)&0xFF)>>2)<<5)|//G
- ((((*inPixel32>>16)&0xFF)>>3)<<0);//B
- }
- }
- else
- {//转换RGB888到RGB565
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBB"to"RRRRRGGGGGGBBBBB"
- //一个像素占2个字节,所以图像中所有像素占用的字节数为width*height*2。由此大小申请内存作为贴图的像素数据。
- tempData=newunsignedchar[width*height*2];
- //将贴图像素数据的地址返回给unsignedshort指针。这样outPixel16就指向了贴图中的第一个像素的数据位置。
- outPixel16=(unsignedshort*)tempData;
- //如果图像的格式为RGB888。取得图像的像素数据地址返回给unsignedchar指针,则inPixel8指向了贴图中第一个像素的R值位置。
- inPixel8=(unsignedchar*)image->getData();
- //遍历图片中所有的像素,逐像素处理。
- for(unsignedinti=0;i<length;++i)
- {//inPixel8指向的是unsignedchar值,通过++操作来取出R,B数据值,然后组成RGB565值。放入outPixel16指向的unsignedshort数据中。
- *outPixel16++=
- (((*inPixel8++&0xFF)>>3)<<11)|//R
- (((*inPixel8++&0xFF)>>2)<<5)|//G
- (((*inPixel8++&0xFF)>>3)<<0);//B
- }
- }
- }
- elseif(pixelFormat==kCCTexture2DPixelFormat_RGBA4444)
- {//转换RGBA8888到RGBA4444
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRGGGGBBBBAAAA"
- //取得图像的像素数据地址返回给unsignedint指针,则inPixel32指向了贴图中第一个像素的数据位置。
- inPixel32=(unsignedint*)image->getData();
- //一个像素占2个字节,所以图像中所有像素占用的字节数为width*height*2。由此大小申请内存作为贴图的像素数据。
- tempData=newunsignedchar[width*height*2];
- //将贴图像素数据的地址返回给unsignedshort指针。这样outPixel16就指向了贴图中的第一个像素的数据位置。
- outPixel16=(unsignedshort*)tempData;
- //遍历图片中所有的像素,逐像素处理。
- for(unsignedinti=0;i<length;++i,B,A各8位数据值,然后组成RGBA4444值。放入outPixel16指向的unsignedshort数据中。
- *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
- }
- }
- elseif(pixelFormat==kCCTexture2DPixelFormat_RGB5A1)
- {//转换RGBA8888到RGBA5551
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRRGGGGGBBBBBA"
- inPixel32=(unsignedint*)image->getData();
- //一个像素占2个字节,所以图像中所有像素占用的字节数为width*height*2。由此大小申请内存作为贴图的像素数据。
- tempData=newunsignedchar[width*height*2];
- //将贴图像素数据的地址返回给unsignedshort指针。这样outPixel16就指向了贴图中的第一个像素的数据位置。
- outPixel16=(unsignedshort*)tempData;
- //遍历图片中所有的像素,逐像素处理。
- for(unsignedinti=0;i<length;++i,A各8位数据值,然后组成RGB5A1值。放入outPixel16指向的unsignedshort数据中。
- *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
- }
- }
- elseif(pixelFormat==kCCTexture2DPixelFormat_A8)
- {//转换RGBA8888到A8,同理,不再赘述
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"AAAAAAAA"
- inPixel32=(unsignedint*)image->getData();
- tempData=newunsignedchar[width*height];
- unsignedchar*outPixel8=tempData;
- for(unsignedinti=0;i<length;++i,++inPixel32)
- {
- *outPixel8++=(*inPixel32>>24)&0xFF;//A
- }
- }
- if(hasAlpha&&pixelFormat==kCCTexture2DPixelFormat_RGB888)
- {//转换RGBA8888到RGB888,同理,不再赘述
- //Convert"RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"to"RRRRRRRRGGGGGGGGBBBBBBBB"
- inPixel32=(unsignedint*)image->getData();
- tempData=newunsignedchar[width*height*3];
- unsignedchar*outPixel8=tempData;
- for(unsignedinti=0;i<length;++i,++inPixel32)
- {
- *outPixel8++=(*inPixel32>>0)&0xFF;//R
- *outPixel8++=(*inPixel32>>8)&0xFF;//G
- *outPixel8++=(*inPixel32>>16)&0xFF;//B
- }
- }
- //因为最终相应像素格式的数据都存放在tempData中,所以这里通过像素数据来生成OpenGL贴图。
- initWithData(tempData,pixelFormat,width,height,imageSize);
- //如果是以上相应格式,则tempData都是新申请的内存块,则在这里释放申请的内存。
- if(tempData!=image->getData())
- {
- delete[]tempData;
- }
- //取得是否有ALPHA渐变通道数据
- m_bHasPremultipliedAlpha=image->isPremultipliedAlpha();
- returntrue;
- }
- //从字符串中创建OpenGL贴图。
- //参1:字符串
- //参2:字体名称
- //参3:字体大小
- boolCCTexture2D::initWithString(constchar*text,floatfontSize)
- {
- returninitWithString(text,CCSizeMake(0,0),kCCTextAlignmentCenter,kCCVerticalTextAlignmentTop,fontName,fontSize);
- }
- //从字符串中创建OpenGL贴图,可指定更多参数。
- //参1:字符串
- //参2:返回参数,代表在屏幕上占用的区域大小
- //参3:文字的横向对齐方式
- //参4:文字的纵向对齐方式
- //参5:字体名称
- //参6:字体大小
- boolCCTexture2D::initWithString(constchar*text,floatfontSize)
- {
- //如果定义使用可变纹理
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //cachethetexturedata
- VolatileTexture::addStringTexture(this,text,dimensions,hAlignment,vAlignment,fontSize);
- #endif
- //定义一个CCImage实例对象
- CCImageimage;
- //定义一个CCImage进行由字符串创建图片时指定的文字对齐方式的变量eAlign
- CCImage::ETextAligneAlign;
- //如果文字纵向对齐方式为顶部对齐。
- if(kCCVerticalTextAlignmentTop==vAlignment)
- {
- //根据文字横向对齐方式的不同分别对eAlign进行设置。
- eAlign=(kCCTextAlignmentCenter==hAlignment)?CCImage::kAlignTop
- :(kCCTextAlignmentLeft==hAlignment)?CCImage::kAlignTopLeft:CCImage::kAlignTopRight;
- }
- //如果文字纵向对齐方式为居中对齐。
- elseif(kCCVerticalTextAlignmentCenter==vAlignment)
- {
- //根据文字横向对齐方式的不同分别对eAlign进行设置。
- eAlign=(kCCTextAlignmentCenter==hAlignment)?CCImage::kAlignCenter
- :(kCCTextAlignmentLeft==hAlignment)?CCImage::kAlignLeft:CCImage::kAlignRight;
- }
- //如果文字纵向对齐方式为底部对齐。
- elseif(kCCVerticalTextAlignmentBottom==vAlignment)
- {
- //根据文字横向对齐方式的不同分别对eAlign进行设置。
- eAlign=(kCCTextAlignmentCenter==hAlignment)?CCImage::kAlignBottom
- :(kCCTextAlignmentLeft==hAlignment)?CCImage::kAlignBottomLeft:CCImage::kAlignBottomRight;
- }
- else
- {
- //其它对齐方式不应存在,故打印错误。
- CCAssert(false,"Notsupportedalignmentformat!");
- }
- //调用CCImage的成员函数由字符串创建出图片数据。
- if(!image.initWithString(text,(int)dimensions.width,(int)dimensions.height,eAlign,(int)fontSize))
- {
- returnfalse;
- }
- //再由CCImage实例对象来创建出OpenGL贴图,初始化纹理。
- returninitWithImage(&image);
- }
- //在指定的位置绘制贴图。
- voidCCTexture2D::drawAtPoint(constCCPoint&point)
- {//定义贴图中图像区域的UV坐标。从左上至右下。
- GLfloatcoordinates[]={
- 0.0f,
- m_fMaxS,
- 0.0f,0.0f,0.0f};
- //取得贴图中图像区域的宽高
- GLfloatwidth=(GLfloat)m_uPixelsWide*m_fMaxS,
- height=(GLfloat)m_uPixelsHigh*m_fMaxT;
- //定义对应的顶点坐标
- GLfloatvertices[]={
- point.x,point.y,
- width+point.x,
- point.x,height+point.y,height+point.y};
- //Shader中使用位置和纹理坐标通道。
- ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position|kCCVertexAttribFlag_TexCoords);
- //后面的代码便用Shader进行渲染
- m_pShaderProgram->use();
- //设置Shader使用的最终结果矩阵
- m_pShaderProgram->setUniformForModelViewProjectionMatrix();
- //将贴图绑定
- ccGLBindTexture2D(m_uName);
- //将vertices设置为顶点位置参数
- glVertexAttribPointer(kCCVertexAttrib_Position,2,GL_FLOAT,GL_FALSE,vertices);
- //将coordinates设置为顶点的纹理坐标参数
- glVertexAttribPointer(kCCVertexAttrib_TexCoords,coordinates);
- //绘制三角形,参1为绘图方式,参2为顶点起始索引,参3为三角形面数。
- glDrawArrays(GL_TRIANGLE_STRIP,4);
- }
- //绘制纹理上的一个区域。
- voidCCTexture2D::drawInRect(constCCRect&rect)
- {//定义贴图中图像区域的UV坐标。从左上至右下。
- GLfloatcoordinates[]={
- 0.0f,
- m_fMaxS,
- 0.0f,0.0f};
- //绘制到的区域
- GLfloatvertices[]={rect.origin.x,rect.origin.y,/*0.0f,*/
- rect.origin.x+rect.size.width,*/
- rect.origin.x,rect.origin.y+rect.size.height,/*0.0f*/};
- //Shader中使用位置和纹理坐标通道。
- ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position|kCCVertexAttribFlag_TexCoords);
- //后面的代码便用Shader进行渲染
- m_pShaderProgram->use();
- //设置Shader使用的最终结果矩阵
- m_pShaderProgram->setUniformForModelViewProjectionMatrix();
- //将贴图绑定
- ccGLBindTexture2D(m_uName);
- //将vertices设置为顶点位置参数
- glVertexAttribPointer(kCCVertexAttrib_Position,4);
- }
- #ifdefCC_SUPPORT_PVRTC
- //如果支持PVR文件的压缩格式。提供的读取PVR压缩文件的函数。
- boolCCTexture2D::initWithPVRTCData(constvoid*data,CCTexture2DPixelFormatpixelFormat)
- {
- if(!(CCConfiguration::sharedConfiguration()->supportsPVRTC()))
- {
- CCLOG("cocos2d:WARNING:PVRTCimagesisnotsupported.");
- this->release();
- returnfalse;
- }
- //产生一个OpenGL的贴图索引。
- glGenTextures(1,&m_uName);
- //绑定纹理
- glBindTexture(GL_TEXTURE_2D,m_uName);
- //设置纹理抗锯齿
- this->setAntiAliasTexParameters();
- //贴图格式
- GLenumformat;
- //数据大小
- GLsizeisize=length*length*bpp/8;
- //根据是否有Alpha来取得贴图格式
- if(hasAlpha){
- format=(bpp==4)?GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
- }else{
- format=(bpp==4)?GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
- }
- if(size<32){
- size=32;
- }
- //加载压缩纹理。
- glCompressedTexImage2D(GL_TEXTURE_2D,level,format,length,size,data);
- //设置其它属性。
- m_tContentSize=CCSizeMake((float)(length),(float)(length));
- m_uPixelsWide=length;
- m_uPixelsHigh=length;
- m_fMaxS=1.0f;
- m_fMaxT=1.0f;
- m_bHasPremultipliedAlpha=PVRHaveAlphaPremultiplied_;
- m_ePixelFormat=pixelFormat;
- returntrue;
- }
- #endif//CC_SUPPORT_PVRTC
- //加载PVR普通文件的函数。
- boolCCTexture2D::initWithPVRFile(constchar*file)
- {
- boolbRet=false;
- //nothingtodowithCCObject::init
- CCTexturePVR*pvr=newCCTexturePVR;
- bRet=pvr->initWithContentsOfFile(file);
- if(bRet)
- {
- pvr->setRetainName(true);//don'tdealloctextureonrelease
- m_uName=pvr->getName();
- m_fMaxS=1.0f;
- m_fMaxT=1.0f;
- m_uPixelsWide=pvr->getWidth();
- m_uPixelsHigh=pvr->getHeight();
- m_tContentSize=CCSizeMake((float)m_uPixelsWide,(float)m_uPixelsHigh);
- m_bHasPremultipliedAlpha=PVRHaveAlphaPremultiplied_;
- m_ePixelFormat=pvr->getFormat();
- m_bHasMipmaps=pvr->getNumberOfMipmaps()>1;
- pvr->release();
- }
- else
- {
- CCLOG("cocos2d:Couldn'tloadPVRimage%s",file);
- }
- returnbRet;
- }
- //设置PVR文件加载时是否使用ALPHA渐变。
- voidCCTexture2D::PVRImagesHavePremultipliedAlpha(boolhaveAlphaPremultiplied)
- {
- PVRHaveAlphaPremultiplied_=haveAlphaPremultiplied;
- }
- //生成多级纹理。
- voidCCTexture2D::generateMipmap()
- {
- CCAssert(m_uPixelsWide==ccNextPOT(m_uPixelsWide)&&m_uPixelsHigh==ccNextPOT(m_uPixelsHigh),"MimpaptextureonlyworksinPOTtextures");
- ccGLBindTexture2D(m_uName);
- glGenerateMipmap(GL_TEXTURE_2D);
- m_bHasMipmaps=true;
- }
- //是否有多级纹理
- boolCCTexture2D::hasMipmaps()
- {
- returnm_bHasMipmaps;
- }
- //设置纹理参数。
- voidCCTexture2D::setTexParameters(ccTexParams*texParams)
- {
- CCAssert((m_uPixelsWide==ccNextPOT(m_uPixelsWide)||texParams->wrapS==GL_CLAMP_TO_EDGE)&&
- (m_uPixelsHigh==ccNextPOT(m_uPixelsHigh)||texParams->wrapT==GL_CLAMP_TO_EDGE),
- "GL_CLAMP_TO_EDGEshouldbeusedinNPOTdimensions");
- ccGLBindTexture2D(m_uName);
- glTexParameteri(GL_TEXTURE_2D,texParams->minFilter);
- glTexParameteri(GL_TEXTURE_2D,texParams->magFilter);
- glTexParameteri(GL_TEXTURE_2D,texParams->wrapS);
- glTexParameteri(GL_TEXTURE_2D,texParams->wrapT);
- }
- //设置为非抗锯齿纹理模式
- voidCCTexture2D::setAliasTexParameters()
- {//绑定纹理
- ccGLBindTexture2D(m_uName);
- //设置多级纹理
- if(!m_bHasMipmaps)
- {
- //设置最小滤波方式为最近点采样,这种方式最快,但有锯齿。
- glTexParameteri(GL_TEXTURE_2D,GL_NEAREST);
- }
- else
- {//设置最小滤波方式为多级纹理方式。
- glTexParameteri(GL_TEXTURE_2D,GL_NEAREST_MIPMAP_NEAREST);
- }
- //设置放大滤波方式为最近点采样
- glTexParameteri(GL_TEXTURE_2D,GL_NEAREST);
- }
- //设置为抗锯齿纹理模式
- voidCCTexture2D::setAntiAliasTexParameters()
- {//绑定纹理
- ccGLBindTexture2D(m_uName);
- //设置多级纹理
- if(!m_bHasMipmaps)
- {
- //设置最小滤波方式为线性过滤,这种方式纹理会有一定程度模糊。
- glTexParameteri(GL_TEXTURE_2D,GL_LINEAR);
- }
- else
- {//设置最小滤波方式为多级纹理方式。
- glTexParameteri(GL_TEXTURE_2D,GL_LINEAR_MIPMAP_NEAREST);
- }
- //设置放大滤波方式为最近点采样
- glTexParameteri(GL_TEXTURE_2D,GL_LINEAR);
- }
- //取得纹理格式的名字字符串
- constchar*CCTexture2D::stringForFormat()
- {
- switch(m_ePixelFormat)
- {
- casekCCTexture2DPixelFormat_RGBA8888:
- return"RGBA8888";
- casekCCTexture2DPixelFormat_RGB888:
- return"RGB888";
- casekCCTexture2DPixelFormat_RGB565:
- return"RGB565";
- casekCCTexture2DPixelFormat_RGBA4444:
- return"RGBA4444";
- casekCCTexture2DPixelFormat_RGB5A1:
- return"RGB5A1";
- casekCCTexture2DPixelFormat_AI88:
- return"AI88";
- casekCCTexture2DPixelFormat_A8:
- return"A8";
- casekCCTexture2DPixelFormat_I8:
- return"I8";
- casekCCTexture2DPixelFormat_PVRTC4:
- return"PVRTC4";
- casekCCTexture2DPixelFormat_PVRTC2:
- return"PVRTC2";
- default:
- CCAssert(false,"unrecognisedpixelformat");
- CCLOG("stringForFormat:%ld,cannotgiveusefulresult",(long)m_ePixelFormat);
- break;
- }
- returnNULL;
- }
- //设置默认带ALPHA通道的纹理格式
- voidCCTexture2D::setDefaultAlphaPixelFormat(CCTexture2DPixelFormatformat)
- {
- g_defaultAlphaPixelFormat=format;
- }
- //取得默认带ALPHA通道的纹理格式
- CCTexture2DPixelFormatCCTexture2D::defaultAlphaPixelFormat()
- {
- returng_defaultAlphaPixelFormat;
- }
- //取得相应纹理格式的色深。
- unsignedintCCTexture2D::bitsPerPixelForFormat(CCTexture2DPixelFormatformat)
- {
- unsignedintret=0;
- switch(format){
- casekCCTexture2DPixelFormat_RGBA8888:
- ret=32;//32位真彩色
- break;
- casekCCTexture2DPixelFormat_RGB888:
- //看起来是用24位,但内部实际是用DWORD来存数据的,所以还是32位。只不过Alpha通道没用。
- ret=32;
- break;
- casekCCTexture2DPixelFormat_RGB565:
- ret=16;
- break;
- casekCCTexture2DPixelFormat_RGBA4444:
- ret=16;
- break;
- casekCCTexture2DPixelFormat_RGB5A1:
- ret=16;
- break;
- casekCCTexture2DPixelFormat_AI88:
- ret=16;
- break;
- casekCCTexture2DPixelFormat_A8:
- ret=8;
- break;
- casekCCTexture2DPixelFormat_I8:
- ret=8;
- break;
- casekCCTexture2DPixelFormat_PVRTC4:
- ret=4;
- break;
- casekCCTexture2DPixelFormat_PVRTC2:
- ret=2;
- break;
- default:
- ret=-1;
- CCAssert(false,"unrecognisedpixelformat");
- CCLOG("bitsPerPixelForFormat:%ld,(long)format);
- break;
- }
- returnret;
- }
- //取得当前纹理格式的色深。
- unsignedintCCTexture2D::bitsPerPixelForFormat()
- {
- returnthis->bitsPerPixelForFormat(m_ePixelFormat);
- }
- NS_CC_END
二.CCTexturePVR:
CCTexturePVR.h:
- #ifndef__CCPVRTEXTURE_H__
- #define__CCPVRTEXTURE_H__
- #include"CCStdC.h"
- #include"CCGL.h"
- #include"cocoa/CCObject.h"
- #include"cocoa/CCArray.h"
- //Cocos2d命名空间
- NS_CC_BEGIN
- //用于多级纹理的结构
- structCCPVRMipmap{
- unsignedchar*address;
- unsignedintlen;
- };
- //最大的多级纹理级数
- enum{
- CC_PVRMIPMAP_MAX=16,
- };
- //所支持的PVR图片格式:
- -RGBA8888
- -BGRA8888
- -RGBA4444
- -RGBA5551
- -RGB565
- -A8
- -I8
- -AI88
- -PVRTC4BPP
- -PVRTC2BPP
- classCCTexturePVR:publicCCObject
- {
- public:
- //构造
- CCTexturePVR();
- //析构
- virtual~CCTexturePVR();
- //成员函数:载入一个PVR图片文件
- boolinitWithContentsOfFile(constchar*path);
- //导出的静态函数:载入一个PVR图片文件。此函数为可供js调用。
- CC_DEPRECATED_ATTRIB一个UTEstaticCCTexturePVR*pvrTextureWithContentsOfFile(constchar*path);
- //静态函数:载入一个PVR图片文件
- staticCCTexturePVR*create(constchar*path);
- //相关属性的获取
- //取得贴图索引
- inlineunsignedintgetName(){returnm_uName;}
- //取得
- inlineunsignedintgetWidth(){returnm_uWidth;}
- inlineunsignedintgetHeight(){returnm_uHeight;}
- //取得是否有ALPHA通道
- inlineboolhasAlpha(){returnm_bHasAlpha;}
- //取得多级纹理的级数
- inlineunsignedintgetNumberOfMipmaps(){returnm_uNumberOfMipmaps;}
- //取得图片格式
- inlineCCTexture2DPixelFormatgetFormat(){returnm_eFormat;}
- //取得是否是供Retain显示屏使用的高清图片。
- inlineboolisRetainName(){returnm_bRetainName;}
- //设置为供Retain显示屏使用的高清图片。
- inlinevoidsetRetainName(boolretainName){m_bRetainName=retainName;}
- private:
- //解压PVR图片数据
- boolunpackPVRData(unsignedchar*data,unsignedintlen);
- //创建OpenGL纹理
- boolcreateGLTexture();
- protected:
- //多级纹理的各级信息结构。
- structCCPVRMipmapm_asMipmaps[CC_PVRMIPMAP_MAX];//pointertomipmapimages
- //多级纹理的最大级别数
- unsignedintm_uNumberOfMipmaps;//numberofmipmapused
- //
- unsignedintm_uTableFormatIndex;
- unsignedintm_uWidth,m_uHeight;
- //贴图索引
- GLuintm_uName;
- //是否有Alpha通道
- boolm_bHasAlpha;
- //是否是供Retain显示屏使用的高清图片。
- boolm_bRetainName;
- //图片格式
- CCTexture2DPixelFormatm_eFormat;
- };
- NS_CC_END
- #endif//__CCPVRTEXTURE_H__
CCTexturePVR.cpp:
- #include"CCTexture2D.h"
- #include"CCTexturePVR.h"
- #include"ccMacros.h"
- #include"CCConfiguration.h"
- #include"support/ccUtils.h"
- #include"CCStdC.h"
- #include"platform/CCFileUtils.h"
- #include"support/zip_support/ZipUtils.h"
- #include"shaders/ccGLStateCache.h"
- #include<ctype.h>
- #include<cctype>
- //Cocos2d命名空间
- NS_CC_BEGIN
- #definePVR_TEXTURE_FLAG_TYPE_MASK0xff
- //PVR文件的信息标志位的各bit位意义
- enum{
- kPVRTextureFlagMipmap=(1<<8),//有多级纹理
- kPVRTextureFlagTwiddle=(1<<9),//istwiddled
- kPVRTextureFlagBumpmap=(1<<10),//是法线贴图(用于产生凹凸感)
- kPVRTextureFlagTiling=(1<<11),//isborderedfortiledpvr
- kPVRTextureFlagCubemap=(1<<12),//是立方体环境映射贴图(一般用于做天空盒)
- kPVRTextureFlagFalseMipCol=(1<<13),//aretherefalsecolouredMIPlevels
- kPVRTextureFlagVolume=(1<<14),//立体纹理,相当于有多层的纹理。
- kPVRTextureFlagAlpha=(1<<15),//v2.1istheretransparencyinfointhetexture
- kPVRTextureFlagVerticalFlip=(1<<16),//v2.1isthetextureverticallyflipped
- };
- //PVR文件头标识
- staticchargPVRTexIdentifier[5]="PVR!";
- //所有PVR文件的格式
- enum
- {
- kPVRTexturePixelTypeRGBA_4444=0x10,
- kPVRTexturePixelTypeRGBA_5551,
- kPVRTexturePixelTypeRGBA_8888,
- kPVRTexturePixelTypeRGB_565,
- kPVRTexturePixelTypeRGB_555,//这个Cocos2d-x暂不支持
- kPVRTexturePixelTypeRGB_888,
- kPVRTexturePixelTypeI_8,
- kPVRTexturePixelTypeAI_88,
- kPVRTexturePixelTypePVRTC_2,
- kPVRTexturePixelTypePVRTC_4,
- kPVRTexturePixelTypeBGRA_8888,
- kPVRTexturePixelTypeA_8,
- };
- //信息数组
- staticconstunsignedinttableFormats[][7]={
- //数组元素的结构为:
- //1-PVR文件格式
- //2-OpenGL内部格式
- //3-OpenGL格式
- //4-OpenGL数据类型
- //5-色深
- //6-是否压缩
- //7-Cocos2d像素格式
- {kPVRTexturePixelTypeRGBA_4444,16,false,kCCTexture2DPixelFormat_RGBA4444},
- {kPVRTexturePixelTypeRGBA_5551,kCCTexture2DPixelFormat_RGB5A1},
- {kPVRTexturePixelTypeRGBA_8888,32,kCCTexture2DPixelFormat_RGBA8888},
- {kPVRTexturePixelTypeRGB_565,kCCTexture2DPixelFormat_RGB565},
- {kPVRTexturePixelTypeRGB_888,24,kCCTexture2DPixelFormat_RGB888},
- {kPVRTexturePixelTypeA_8,8,kCCTexture2DPixelFormat_A8},
- {kPVRTexturePixelTypeI_8,kCCTexture2DPixelFormat_I8},
- {kPVRTexturePixelTypeAI_88,kCCTexture2DPixelFormat_AI88},
- #if(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)
- //如果程序运行在IOS上,还可支持以下信息
- {kPVRTexturePixelTypePVRTC_2,GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG,(unsignedint)-1,(unsignedint)-1,true,kCCTexture2DPixelFormat_PVRTC2},
- {kPVRTexturePixelTypePVRTC_4,GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,4,kCCTexture2DPixelFormat_PVRTC4},
- {kPVRTexturePixelTypeBGRA_8888,GL_BGRA,
- #endif
- };
- //信息表的元素数量
- #defineMAX_TABLE_ELEMENTS(sizeof(tableFormats)/sizeof(tableFormats[0]))
- //
- enum{
- kCCInternalPVRTextureFormat,
- kCCInternalOpenGLInternalFormat,
- kCCInternalOpenGLFormat,
- kCCInternalOpenGLType,
- kCCInternalBPP,
- kCCInternalCompressedImage,
- kCCInternalCCTexture2DPixelFormat,
- };
- //PVR文件头信息结构
- typedefstruct_PVRTexHeader
- {
- unsignedintheaderLength;//头信息长度
- unsignedintheight;//高
- unsignedintwidth;//宽
- unsignedintnumMipmaps;//是否有多级纹理
- unsignedintflags;//标记位
- unsignedintdataLength;//后面的像素数据长度
- unsignedintbpp;//色深
- unsignedintbitmaskRed;//对应红色的像素位
- unsignedintbitmaskGreen;//对应绿色的像素位
- unsignedintbitmaskBlue;//对应蓝色的像素位
- unsignedintbitmaskAlpha;//对应ALPHA色的像素位
- unsignedintpvrTag;//
- unsignedintnumSurfs;//是否有多层
- }PVRTexHeader;
- //构造函数
- CCTexturePVR::CCTexturePVR()
- :m_uTableFormatIndex(0)
- ,m_uNumberOfMipmaps(0)
- ,m_uWidth(0)
- ,m_uHeight(0)
- ,m_bRetainName(false)
- ,m_bHasAlpha(false)
- ,m_eFormat(kCCTexture2DPixelFormat_Default)
- {
- }
- //析构函数
- CCTexturePVR::~CCTexturePVR()
- {
- CCLOGINFO("cocos2d:deallocingCCTexturePVR");
- //释放OpenGL贴图
- if(m_uName!=0&&!m_bRetainName)
- {
- ccGLDeleteTexture(m_uName);
- }
- }
- //解压PVR像素数据
- boolCCTexturePVR::unpackPVRData(unsignedchar*data,unsignedintlen)
- {
- boolsuccess=false;
- PVRTexHeader*header=NULL;
- unsignedintflags,pvrTag;
- unsignedintdataLength=0,dataOffset=0,dataSize=0;
- unsignedintblockSize=0,widthBlocks=0,heightBlocks=0;
- unsignedintwidth=0,height=0,bpp=4;
- unsignedchar*bytes=NULL;
- unsignedintformatFlags;
- //将数据地址转为头信息指针,这个就可以直接通过结构指针进行存取。
- header=(PVRTexHeader*)data;
- //格式有效性检查
- pvrTag=CC_SWAP_INT32_LITTLE_TO_HOST(header->pvrTag);
- /*
- Checkthatgivendatareallyrepresentspvrtexture
- [0]='P'
- [1]='V'
- [2]='R'
- [3]='!'
- */
- if(gPVRTexIdentifier[0]!=((pvrTag>>0)&0xff)||
- gPVRTexIdentifier[1]!=((pvrTag>>8)&0xff)||
- gPVRTexIdentifier[2]!=((pvrTag>>16)&0xff)||
- gPVRTexIdentifier[3]!=((pvrTag>>24)&0xff))
- {
- CCLOG("UnsupportedPVRformat.UsetheLegacyformatuntilthenewformatissupported");
- returnfalse;
- }
- //取得配置信息
- CCConfiguration*configuration=CCConfiguration::sharedConfiguration();
- //取得标记
- flags=CC_SWAP_INT32_LITTLE_TO_HOST(header->flags);
- formatFlags=flags&PVR_TEXTURE_FLAG_TYPE_MASK;
- boolflipped=(flags&kPVRTextureFlagVerticalFlip)?true:false;
- if(flipped)
- {
- CCLOG("cocos2d:WARNING:Imageisflipped.RegenerateitusingPVRTexTool");
- }
- //查看是否支持非2的幂次方大小的纹理
- if(!configuration->supportsNPOT()&&
- (header->width!=ccNextPOT(header->width)||header->height!=ccNextPOT(header->height)))
- {
- CCLOG("cocos2d:ERROR:LodinganNPOTtexture(%dx%d)butisnotsupportedonthisdevice",header->width,header->height);
- returnfalse;
- }
- //遍历所有的格式信息数据,找到对应的格式信息。
- for(m_uTableFormatIndex=0;m_uTableFormatIndex<(unsignedint)MAX_TABLE_ELEMENTS;m_uTableFormatIndex++)
- {
- if(tableFormats[m_uTableFormatIndex][kCCInternalPVRTextureFormat]==formatFlags)
- {
- //Resetnumofmipmaps
- m_uNumberOfMipmaps=0;
- //取得图片大小
- m_uWidth=width=CC_SWAP_INT32_LITTLE_TO_HOST(header->width);
- m_uHeight=height=CC_SWAP_INT32_LITTLE_TO_HOST(header->height);
- //检查是否有ALPHA通道
- if(CC_SWAP_INT32_LITTLE_TO_HOST(header->bitmaskAlpha))
- {
- m_bHasAlpha=true;
- }
- else
- {
- m_bHasAlpha=false;
- }
- //取得数据长度
- dataLength=CC_SWAP_INT32_LITTLE_TO_HOST(header->dataLength);
- //将数据指针偏移到头信息之后,即像素数据所在位置
- bytes=((unsignedchar*)data)+sizeof(PVRTexHeader);
- m_eFormat=(CCTexture2DPixelFormat)(tableFormats[m_uTableFormatIndex][kCCInternalCCTexture2DPixelFormat]);
- bpp=tableFormats[m_uTableFormatIndex][kCCInternalBPP];
- //遍历每个多级纹理图像块
- while(dataOffset<dataLength)
- {
- switch(formatFlags){
- casekPVRTexturePixelTypePVRTC_2:
- blockSize=8*4;//Pixelbypixelblocksizefor2bpp
- widthBlocks=width/8;
- heightBlocks=height/4;
- break;
- casekPVRTexturePixelTypePVRTC_4:
- blockSize=4*4;//Pixelbypixelblocksizefor4bpp
- widthBlocks=width/4;
- heightBlocks=height/4;
- break;
- casekPVRTexturePixelTypeBGRA_8888:
- if(CCConfiguration::sharedConfiguration()->supportsBGRA8888()==false)
- {
- CCLOG("cocos2d:TexturePVR.BGRA8888notsupportedonthisdevice");
- returnfalse;
- }
- default:
- blockSize=1;
- widthBlocks=width;
- heightBlocks=height;
- break;
- }
- //Clamptominimumnumberofblocks
- if(widthBlocks<2)
- {
- widthBlocks=2;
- }
- if(heightBlocks<2)
- {
- heightBlocks=2;
- }
- dataSize=widthBlocks*heightBlocks*((blockSize*bpp)/8);
- unsignedintpacketLength=(dataLength-dataOffset);
- packetLength=packetLength>dataSize?dataSize:packetLength;
- //记录每个多级纹理图像块的像素数据地址和长度。
- m_asMipmaps[m_uNumberOfMipmaps].address=bytes+dataOffset;
- m_asMipmaps[m_uNumberOfMipmaps].len=packetLength;
- m_uNumberOfMipmaps++;
- //检查是否超出最大级数
- CCAssert(m_uNumberOfMipmaps<CC_PVRMIPMAP_MAX,
- "TexturePVR:Maximumnumberofmimpapsreached.IncreatetheCC_PVRMIPMAP_MAXvalue");
- //偏移到下一个多级纹理图像块。
- dataOffset+=packetLength;
- //大小减为原来1/2。
- width=MAX(width>>1,1);
- height=MAX(height>>1,1);
- }
- //读取完成
- success=true;
- break;
- }
- }
- //成功判断
- if(!success)
- {
- CCLOG("cocos2d:WARNING:UnsupportedPVRPixelFormat:0x%2x.Re-encodeitwithaOpenGLpixelformatvariant",formatFlags);
- }
- returnsuccess;
- }
- //创建OpenGL贴图
- boolCCTexturePVR::createGLTexture()
- {
- //保存宽高
- unsignedintwidth=m_uWidth;
- unsignedintheight=m_uHeight;
- GLenumerr;
- //如果文件中有多级纹理
- if(m_uNumberOfMipmaps>0)
- {
- //先释放原来的纹理
- if(m_uName!=0)
- {
- ccGLDeleteTexture(m_uName);
- }
- //像素数据每字节对齐
- glPixelStorei(GL_UNPACK_ALIGNMENT,1);
- //产生OpenGL贴图
- glGenTextures(1,&m_uName);
- glBindTexture(GL_TEXTURE_2D,m_uName);
- //如果无多级纹理,设置最小滤波方式为线性过滤,产生抗锯齿效果。
- if(m_uNumberOfMipmaps==1)
- {
- glTexParameteri(GL_TEXTURE_2D,GL_LINEAR);
- }
- else
- {//设置最小滤波方式为最近点采样,这种方式有锯齿。
- glTexParameteri(GL_TEXTURE_2D,GL_LINEAR_MIPMAP_NEAREST);
- }
- //设置最大滤波方式为线性过滤
- glTexParameteri(GL_TEXTURE_2D,GL_CLAMP_TO_EDGE);
- }
- //检错
- CHECK_GL_ERROR_DEBUG();//cleanpossibleGLerror
- //取得对应格式的相关信息。
- GLenuminternalFormat=tableFormats[m_uTableFormatIndex][kCCInternalOpenGLInternalFormat];
- GLenumformat=tableFormats[m_uTableFormatIndex][kCCInternalOpenGLFormat];
- GLenumtype=tableFormats[m_uTableFormatIndex][kCCInternalOpenGLType];
- boolcompressed=(0==tableFormats[m_uTableFormatIndex][kCCInternalCompressedImage])?false:true;
- //循环产生多级纹理贴图。
- for(unsignedinti=0;i<m_uNumberOfMipmaps;++i)
- {
- //检查配置信息是否支持压缩格式。
- if(compressed&&!CCConfiguration::sharedConfiguration()->supportsPVRTC())
- {
- CCLOG("cocos2d:WARNING:PVRTCimagesarenotsupported");
- returnfalse;
- }
- //取得当前级别的图像块的像素数据地址和长度。
- unsignedchar*data=m_asMipmaps[i].address;
- unsignedintdatalen=m_asMipmaps[i].len;
- //如果是压缩格式,则产生压缩格式的贴图。
- if(compressed)
- {
- glCompressedTexImage2D(GL_TEXTURE_2D,i,internalFormat,datalen,data);
- }
- else
- {//产生一般格式的贴图。
- glTexImage2D(GL_TEXTURE_2D,type,data);
- }
- //如果是非2的幂次方大小,则提示。
- if(i>0&&(width!=height||ccNextPOT(width)!=width))
- {
- CCLOG("cocos2d:TexturePVR.WARNING.Mipmaplevel%uisnotsquared.Texturewon'trendercorrectly.width=%u!=height=%u",height);
- }
- //检错
- err=glGetError();
- if(err!=GL_NO_ERROR)
- {
- CCLOG("cocos2d:TexturePVR:Erroruploadingcompressedtexturelevel:%u.glError:0x%04X",err);
- returnfalse;
- }
- //变为原来大小的1/2。
- width=MAX(width>>1,1);
- }
- returntrue;
- }
- //成员函数:加载PVR图片
- boolCCTexturePVR::initWithContentsOfFile(constchar*path)
- {
- unsignedchar*pvrdata=NULL;
- intpvrlen=0;
- //定义字符串变量,存储转换为小写的路径字符串。
- std::stringlowerCase(path);
- for(unsignedinti=0;i<lowerCase.length();++i)
- {
- lowerCase[i]=tolower(lowerCase[i]);
- }
- //检查是否是ccz格式。
- if(lowerCase.find(".ccz")!=std::string::npos)
- {
- //调用压缩库函数将文件数据读取到为pvrdata申请的内存中。取得其大小存入pvrlen变量中。
- pvrlen=ZipUtils::ccInflateCCZFile(path,&pvrdata);
- }
- //检查是否是gz格式。
- elseif(lowerCase.find(".gz")!=std::string::npos)
- {
- //调用压缩库函数将文件数据读取到为pvrdata申请的内存中。取得其大小存入pvrlen变量中。
- pvrlen=ZipUtils::ccInflateGZipFile(path,&pvrdata);
- }
- else
- {
- //普通PVR文件,将文件数据读取到一块内存中返回给pvrdata。取得其大小存入pvrlen变量中。
- pvrdata=CCFileUtils::sharedFileUtils()->getFileData(path,"rb",(unsignedlong*)(&pvrlen));
- }
- //如果读取失败则返回
- if(pvrlen<0)
- {
- this->release();
- returnfalse;
- }
- m_uNumberOfMipmaps=0;
- m_uName=0;
- m_uWidth=m_uHeight=0;
- m_bHasAlpha=false;
- m_bRetainName=false;
- //如果解压数据失败则返回。
- //解压后,如果创建贴图失败则返回。
- if(!unpackPVRData(pvrdata,pvrlen)||!createGLTexture())
- {
- CC_SAFE_DELETE_ARRAY(pvrdata);
- this->release();
- returnfalse;
- }
- //释放数据占用的内存。
- CC_SAFE_DELETE_ARRAY(pvrdata);
- returntrue;
- }
- //导出的静态函数:加载PVR图片
- CCTexturePVR*CCTexturePVR::pvrTextureWithContentsOfFile(constchar*path)
- {
- returnCCTexturePVR::create(path);
- }
- //静态函数:加载PVR图片
- CCTexturePVR*CCTexturePVR::create(constchar*path)
- {
- //new一个新的CCTexturePVR
- CCTexturePVR*pTexture=newCCTexturePVR();
- if(pTexture)
- {
- //调用成员函数加载PVR图片
- if(pTexture->initWithContentsOfFile(path))
- {
- //如果成功,设置交由内存管理器使用引用计数器进行内存管理。
- pTexture->autorelease();
- }
- else
- {
- //否则释放纹理
- deletepTexture;
- pTexture=NULL;
- }
- }
- //返回这个CCTexturePVR
- returnpTexture;
- }
- NS_CC_END
三.CCTextureCache:
打开CCTextureCache.h:
- #ifndef__CCTEXTURE_CACHE_H__
- #define__CCTEXTURE_CACHE_H__
- //由CCObject派生
- #include"cocoa/CCObject.h"
- //需要用到字典
- #include"cocoa/CCDictionary.h"
- #include"textures/CCTexture2D.h"
- #include<string>
- //这里用到CCImage类和STL容器之一list
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- #include"platform/CCImage.h"
- #include<list>
- #endif
- //Cocos2d命名空间
- NS_CC_BEGIN
- //用到线程锁
- classCCLock;
- //用到CCImage处理图片
- classCCImage;
- //纹理管理器
- classCC_DLLCCTextureCache:publicCCObject
- {
- protected:
- //字典对象指针。
- CCDictionary*m_pTextures;
- //线程临界区。用于锁定字典访问,貌似用不到。这里屏蔽了~
- //pthread_mutex_t*m_pDictLock;
- private:
- //设置多线程加载图片时的回调函数。
- voidaddImageAsyncCallBack(floatdt);
- public:
- //构造函数
- CCTextureCache();
- //析构函数
- virtual~CCTextureCache();
- //取得当前类描述
- constchar*description(void);
- //取得当前字典的快照(拷贝)
- CCDictionary*snapshotTextures();
- //返回唯一纹理管理器的实例指针
- staticCCTextureCache*sharedTextureCache();
- //销毁唯一纹理管理器的实例指针
- staticvoidpurgeSharedTextureCache();
- //加载一个图片生成纹理,文件名做为字典的查询对应关键字。返回生成的纹理指针,支持png,bmp,tiff,jpeg,pvr,gif等格式。
- CCTexture2D*addImage(constchar*fileimage);
- //此函数可以支持多线程载入图片,调用时会创建一个线程进行异步加载,加载成功后由主线程调用设置的回调函数,当然创建的纹理会做为参数传递。支持png和jpg
- voidaddImageAsync(constchar*path,CCObject*target,SEL_CallFuncOselector);
- //加载一个图片生成纹理,指定参数key(其实要求是图片的相对路径字符串)做为字典的查询对应关键字。
- CCTexture2D*addUIImage(CCImage*image,constchar*key);
- //通过查询关键字(其实要求是图片的相对路径字符串)从字典里找到对应的纹理。
- CCTexture2D*textureForKey(constchar*key);
- //清空字典,释放所有纹理。
- voidremoveAllTextures();
- //清除未被外部使用的纹理。怎么知道未使用呢?因为在Cocos2d-x中使用“引用计数器”来管理各种资源的使用情况,纹理也不例外。在资源类构造时,纹理的计数器值为0,但由CCTextureCache来创建完成后,会对纹理的资源计数器做加1操作以通知纹理说“你现在被我占用呢”。如果纹理被外部使用,应该再次调用其资源计数器做加1操作,退出使用时做减1操作通知其“我现在不用你了”。所以这里只需要遍历下计数器值为1的纹理即未被外部使用的纹理进行释放即可。
- voidremoveUnusedTextures();
- //移除一个纹理
- voidremoveTexture(CCTexture2D*texture);
- //由字典查询关键字找到相应纹理并移除。
- voidremoveTextureForKey(constchar*textureKeyName);
- //打印出当前管理的纹理信息,包括现在纹理占用的内存和总的纹理内存。
- voiddumpCachedTextureInfo();
- #ifdefCC_SUPPORT_PVRTC
- //如果开启支持PVR的压缩格式,这里提供加载PVR压缩文件生成纹理的函数。
- //参1:PVR压缩文件名
- //参2:压缩质量参数,只能设为2或4,4比2质量高,但压缩比低。2则相反。
- //参3:是否有Alpha通道。这里会根据是否有ALPHA通道以生成相应的默认纹理格式。
- //参4:图片必须是2的幂次方大小的正方形,所以这里只需要填写一下宽度,也就是图片大小。
- CCTexture2D*addPVRTCImage(constchar*fileimage,intwidth);
- #endif//CC_SUPPORT_PVRTC
- //加载普通的PVR图片文件生成纹理。
- CCTexture2D*addPVRImage(constchar*filename);
- //如果CC_ENABLE_CACHE_TEXTURE_DATA宏定义为可用(即值为1),则调用此函数会将所有的纹理都预加载进内存生成相应纹理。
- staticvoidreloadAllTextures();
- };
- //如果定义了CC_ENABLE_CACHE_TEXTURE_DATA,这里定义一个新的类
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //新定义的类名称为VolatileTexture,意思是多变纹理。这里代表了多种数据源生成的纹理的管理器。
- classVolatileTexture
- {
- //这里声明了一个枚举,代表了多变纹理对应的几种数据源类型
- typedefenum{
- kInvalid=0,//无效未加载任何数据的状态
- kImageFile,//图片文件
- kImageData,//内存中的图片数据
- kString,//字符串
- kImage,//图片对象(CCImage)
- }ccCachedImageType;
- public:
- //构造
- VolatileTexture(CCTexture2D*t);
- //析构
- ~VolatileTexture();
- //静态函数:通过图片文件生成的纹理及相关信息生成一个多变纹理并将其指针放入容器。
- staticvoidaddImageTexture(CCTexture2D*tt,constchar*imageFileName,CCImage::EImageFormatformat);
- //静态函数:通过字符串生成的纹理及相关信息生成一个多变纹理并将其指针放入容器。
- staticvoidaddStringTexture(CCTexture2D*tt,constchar*text,CCTextAlignmentalignment,
- CCVerticalTextAlignmentvAlignment,constchar*fontName,floatfontSize);
- //通过图片数据生成的纹理及相关信息生成一个多变纹理并将其指针放入容器。
- staticvoidaddDataTexture(CCTexture2D*tt,void*data,constCCSize&contentSize);
- //通过图片对象生成的纹理及相关信息生成一个多变纹理并将其指针放入容器。
- staticvoidaddCCImage(CCTexture2D*tt,CCImage*image);
- //通过纹理指针参数从容器中删除对应的多变纹理
- staticvoidremoveTexture(CCTexture2D*t);
- //重新载入所有的纹理
- staticvoidreloadAllTextures();
- public:
- //静态多变纹理指针容器,用来存储所有的多变纹理对象指针。
- staticstd::list<VolatileTexture*>textures;
- //是否正在进行全部重新载入
- staticboolisReloading;
- private:
- //通过纹理指针参数从容器找到对应的多变纹理对象指针
- staticVolatileTexture*findVolotileTexture(CCTexture2D*tt);
- protected:
- //与当前多变纹理对应的纹理指针
- CCTexture2D*texture;
- //对应的图片对象
- CCImage*uiImage;
- //数据源类型
- ccCachedImageTypem_eCashedImageType;
- //纹理数据指针
- void*m_pTextureData;
- //纹理的实际大小
- CCSizem_TextureSize;
- //纹理的像素格式
- CCTexture2DPixelFormatm_PixelFormat;
- //对应的图片名称
- std::stringm_strFileName;
- //图片的像素格式
- CCImage::EImageFormatm_FmtImage;
- //图片的大小
- CCSizem_size;
- //横向文字的对齐方式
- CCTextAlignmentm_alignment;
- //纵向文字的对齐方式
- CCVerticalTextAlignmentm_vAlignment;
- //字体名称
- std::stringm_strFontName;
- //文字
- std::stringm_strText;
- //字体大小
- floatm_fFontSize;
- };
- #endif
- NS_CC_END
- #endif//__CCTEXTURE_CACHE_H__
然后是CPP文件:
- #include"CCTextureCache.h"
- #include"CCTexture2D.h"
- #include"ccMacros.h"
- #include"CCDirector.h"
- #include"platform/platform.h"
- #include"platform/CCFileUtils.h"
- #include"platform/CCThread.h"
- #include"platform/CCImage.h"
- #include"support/ccUtils.h"
- #include"CCScheduler.h"
- #include"cocoa/CCString.h"
- #include<errno.h>
- #include<stack>
- #include<string>
- #include<cctype>
- #include<queue>
- #include<list>
- #include<pthread.h>
- #include<semaphore.h>
- //使用标准库命名空间
- usingnamespacestd;
- //使用Cocos2d命名空间
- NS_CC_BEGIN
- //异步加载所用的消息结构
- typedefstruct_AsyncStruct
- {
- std::stringfilename;//文件名
- CCObject*target;//调用者
- SEL_CallFuncOselector;//载回完的回调函数
- }AsyncStruct;
- //图片信息
- typedefstruct_ImageInfo
- {
- AsyncStruct*asyncStruct;//异步加载消息结构
- CCImage*image;//图片指针
- CCImage::EImageFormatimageType//图片类型
- }ImageInfo;
- //加载图片的线程
- staticpthread_ts_loadingThread;
- //用于读取异步消息队列的线程临界区
- staticpthread_mutex_ts_asyncStructQueueMutex;
- //用于存储图片信息结构处理的临界区
- staticpthread_mutex_ts_ImageInfoMutex;
- //信号量指针。信号量是当前进程中的多个线程通信的一种方式。
- staticsem_t*s_pSem=NULL;
- //多线程加载图片的数量。
- staticunsignedlongs_nAsyncRefCount=0;
- //如果是IOS平台,则定义是否使用信号量命名。
- #ifCC_TARGET_PLATFORM==CC_PLATFORM_IOS
- #defineCC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE1
- #else
- #defineCC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE0
- #endif
- //如果使用信号量命名,则定义命名的字符串宏,否则定义静态全局的信号量结构。
- #ifCC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
- #defineCC_ASYNC_TEXTURE_CACHE_SEMAPHORE"ccAsync"
- #else
- staticsem_ts_sem;
- #endif
- //是否在当前加载线程处理完手上的活儿就退出。
- staticboolneed_quit=false;
- //异步加载图片的消息结构指针容器,即消息队列。
- staticstd::queue<AsyncStruct*>*s_pAsyncStructQueue=NULL;
- //异步存储图片信息结构指针的容器。
- staticstd::queue<ImageInfo*>*s_pImageQueue=NULL;
- //通过文件扩展名取得图片格式
- staticCCImage::EImageFormatcomputeImageFormatType(string&filename)
- {
- CCImage::EImageFormatret=CCImage::kFmtUnKnown;
- //JPG
- if((std::string::npos!=filename.find(".jpg"))||(std::string::npos!=filename.find(".jpeg")))
- {
- ret=CCImage::kFmtJpg;
- }//PNG
- elseif((std::string::npos!=filename.find(".png"))||(std::string::npos!=filename.find(".PNG")))
- {
- ret=CCImage::kFmtPng;
- }//TIFF
- elseif((std::string::npos!=filename.find(".tiff"))||(std::string::npos!=filename.find(".TIFF")))
- {
- ret=CCImage::kFmtTiff;
- }
- returnret;
- }
- //加载图片的线程函数
- staticvoid*loadImage(void*data)
- {
- //创建一个线程信息对象
- CCThreadthread;
- thread.createAutoreleasePool();
- //多线程加载消息结构
- AsyncStruct*pAsyncStruct=NULL;
- //线程将处理所有随时要进行多线程加载的图片,所以会有一个While循环。
- while(true)
- {
- //当前线程等待信号量变为非零值,并减1。
- intsemWaitRet=sem_wait(s_pSem);
- //如果信号量为负值,打印出错信息并中断。
- if(semWaitRet<0)
- {
- CCLOG("CCTextureCacheasyncthreadsemaphoreerror:%s\n",strerror(errno));
- break;
- }
- //取得全局的异步加载信息结构指针容器
- std::queue<AsyncStruct*>*pQueue=s_pAsyncStructQueue;
- //下面代码作为临界区上锁
- pthread_mutex_lock(&s_asyncStructQueueMutex);
- //如果没有需要异步加载的图片
- if(pQueue->empty())
- {
- //解锁临界区
- pthread_mutex_unlock(&s_asyncStructQueueMutex);
- //如果退出线程标记为true则中断退出,否则继续。
- if(need_quit)
- break;
- else
- continue;
- }
- else
- {
- //如果有需要异步加载的图片,则从队列中取第一个消息指针保存在变量pAsyncStruct中随后将其从队列中移除。
- pAsyncStruct=pQueue->front();
- pQueue->pop();
- //解锁临界区
- pthread_mutex_unlock(&s_asyncStructQueueMutex);
- }
- //取得要进行异步加载的图片名称
- constchar*filename=pAsyncStruct->filename.c_str();
- //取得图片类型
- CCImage::EImageFormatimageType=computeImageFormatType(pAsyncStruct->filename);
- //如果不是PNG,JPG或TIFF就不支持了。打印错误后进行相应处理。
- if(imageType==CCImage::kFmtUnKnown)
- {
- CCLOG("unsupporttedformat%s",filename);
- deletepAsyncStruct;
- continue;
- }
- //如果是有效格式,生成一个新的CCImage对象
- CCImage*pImage=newCCImage();
- //由文件名和图片格式将图片加载到CCImage中。
- if(!pImage->initWithImageFileThreadSafe(filename,imageType))
- {//如果失败,释放CCImage对象并打印错误。
- deletepImage;
- CCLOG("cannotload%s",filename);
- continue;
- }
- //动态创建一个新的图片信息结构并填充相应信息
- ImageInfo*pImageInfo=newImageInfo();
- pImageInfo->asyncStruct=pAsyncStruct;
- pImageInfo->image=pImage;
- pImageInfo->imageType=imageType;
- //下面代码作为临界区上锁
- pthread_mutex_lock(&s_ImageInfoMutex);
- //将新的图片信息放入图片信息结构容器。
- s_pImageQueue->push(pImageInfo);
- //解锁临界区
- pthread_mutex_unlock(&s_ImageInfoMutex);
- }
- //如果退出循环,释放信号量
- if(s_pSem!=NULL)
- {
- #ifCC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
- sem_unlink(CC_ASYNC_TEXTURE_CACHE_SEMAPHORE);
- sem_close(s_pSem);
- #else
- sem_destroy(s_pSem);
- #endif
- s_pSem=NULL;
- //释放多线程加载所用的消息队列和与之对应的图片信息队列。
- deletes_pAsyncStructQueue;
- deletes_pImageQueue;
- }
- return0;
- }
- //唯一的全局纹理数据缓冲区对象指针
- staticCCTextureCache*g_sharedTextureCache=NULL;
- //取得唯一的全局纹理数据缓冲区对象指针
- CCTextureCache*CCTextureCache::sharedTextureCache()
- {
- if(!g_sharedTextureCache)
- {
- g_sharedTextureCache=newCCTextureCache();
- }
- returng_sharedTextureCache;
- }
- //构造函数
- CCTextureCache::CCTextureCache()
- {
- CCAssert(g_sharedTextureCache==NULL,"Attemptedtoallocateasecondinstanceofasingleton.");
- //生成一个字典
- m_pTextures=newCCDictionary();
- }
- //析构函数
- CCTextureCache::~CCTextureCache()
- {
- CCLOGINFO("cocos2d:deallocingCCTextureCache.");
- need_quit=true;
- if(s_pSem!=NULL)
- {
- sem_post(s_pSem);
- }
- //释放字典
- CC_SAFE_RELEASE(m_pTextures);
- }
- //释放唯一的全局纹理数据缓冲区对象
- voidCCTextureCache::purgeSharedTextureCache()
- {
- CC_SAFE_RELEASE_NULL(g_sharedTextureCache);
- }
- //取得当前类描述
- constchar*CCTextureCache::description()
- {
- returnCCString::createWithFormat("<CCTextureCache|Numberoftextures=%u>",m_pTextures->count())->getCString();
- }
- //取得当前字典的快照
- CCDictionary*CCTextureCache::snapshotTextures()
- {
- //动态创建一个新的字典
- CCDictionary*pRet=newCCDictionary();
- CCDictElement*pElement=NULL;
- //遍历原来字典将数据填充到新字典中
- CCDICT_FOREACH(m_pTextures,pElement)
- {
- pRet->setObject(pElement->getObject(),pElement->getStrKey());
- }
- returnpRet;
- }
- //使用多线程载入图片。
- //参1:图片相对路径名。
- //参2:载入完成后要通知的对象。
- //参3:载入完成后要通知对象调用的函数。
- voidCCTextureCache::addImageAsync(constchar*path,SEL_CallFuncOselector)
- {
- //文件名不能为空
- CCAssert(path!=NULL,"TextureCache:fileimageMUSTnotbeNULL");
- //定义一个纹理指针并置空
- CCTexture2D*texture=NULL;
- //创建字符串pathKey做为字典查询关键字。
- std::stringpathKey=path;
- //取得图片所在位置的全路径名
- pathKey=CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(pathKey.c_str());
- //先查询一下是否字典里已经有了此纹理。
- texture=(CCTexture2D*)m_pTextures->objectForKey(pathKey.c_str());
- std::stringfullpath=pathKey;
- //如果已经有了,则直接把纹理做为参数调用要通知的对象的函数。
- if(texture!=NULL)
- {
- if(target&&selector)
- {
- (target->*selector)(texture);
- }
- return;
- }
- //如果是第一次调用多线程载入,创建信号量并进行相应初始化。
- if(s_pSem==NULL)
- {
- //判断是否使用信号量命名,如果是,创建一个信号量返回其地址给指针s_pSem。
- #ifCC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
- s_pSem=sem_open(CC_ASYNC_TEXTURE_CACHE_SEMAPHORE,O_CREAT,0644,0);
- if(s_pSem==SEM_FAILED)
- {
- CCLOG("CCTextureCacheasyncthreadsemaphoreiniterror:%s\n",strerror(errno));
- s_pSem=NULL;
- return;
- }
- #else
- //如果不使用信号量命名,直接用sem_init来初始化信号量对象s_sem。
- intsemInitRet=sem_init(&s_sem,0);
- if(semInitRet<0)
- {
- //如果失败,打印出错并退出。
- CCLOG("CCTextureCacheasyncthreadsemaphoreiniterror:%s\n",strerror(errno));
- return;
- }
- //如果成功,将信号量对象地址给指针s_pSem。
- s_pSem=&s_sem;
- #endif
- //建立加载消息队列
- s_pAsyncStructQueue=newqueue<AsyncStruct*>();
- //建立加载的图片信息结构队列
- s_pImageQueue=newqueue<ImageInfo*>();
- //线程锁初始化
- pthread_mutex_init(&s_asyncStructQueueMutex,NULL);
- pthread_mutex_init(&s_ImageInfoMutex,NULL);
- //创建加载线程。
- pthread_create(&s_loadingThread,NULL,loadImage,NULL);
- //将退出指令设为false。
- need_quit=false;
- }
- //多线程加载图片的引用计数器如果为0,
- if(0==s_nAsyncRefCount)
- {
- //将addImageAsyncCallBack函数加入显示设备上的回调函数处理器中。
- CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack),this,false);
- }
- //计数器加1
- ++s_nAsyncRefCount;
- //
- if(target)
- {
- target->retain();
- }
- //产生一个新的加载消息,放入加载消息队列中。
- AsyncStruct*data=newAsyncStruct();
- data->filename=fullpath.c_str();
- data->target=target;
- data->selector=selector;
- //当然,放入时得锁一下,放入后再解锁。
- pthread_mutex_lock(&s_asyncStructQueueMutex);
- s_pAsyncStructQueue->push(data);
- pthread_mutex_unlock(&s_asyncStructQueueMutex);
- //给信号量加1,sem_post是原子操作,即多个线程同时调用并不会产生冲突。
- sem_post(s_pSem);
- }
- //多线程加载图片时的回调函数。
- voidCCTextureCache::addImageAsyncCallBack(floatdt)
- {
- //取得多线程加载的图片信息队列
- std::queue<ImageInfo*>*imagesQueue=s_pImageQueue;
- //下面代码作为临界区上锁
- pthread_mutex_lock(&s_ImageInfoMutex);
- //如果图片信息队列为空直接解锁,否则进行处理
- if(imagesQueue->empty())
- {
- pthread_mutex_unlock(&s_ImageInfoMutex);
- }
- else
- {
- //取出图片信息队列的头一个信息从队列中弹出。
- ImageInfo*pImageInfo=imagesQueue->front();
- imagesQueue->pop();
- //解锁临界区
- pthread_mutex_unlock(&s_ImageInfoMutex);
- //取得信息中的加载消息。
- AsyncStruct*pAsyncStruct=pImageInfo->asyncStruct;
- //取得图片信息中的CCImage指针。
- CCImage*pImage=pImageInfo->image;
- //取得加载完成后要通知的对象以及要调用的函数。
- CCObject*target=pAsyncStruct->target;
- SEL_CallFuncOselector=pAsyncStruct->selector;
- //取得图片文件名
- constchar*filename=pAsyncStruct->filename.c_str();
- //新建一个纹理。
- CCTexture2D*texture=newCCTexture2D();
- //使用CCImage指针pImage来初始化纹理生成OpenGL贴图。
- #if0//TODO:(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)
- texture->initWithImage(pImage,kCCResolutioniPhone);
- #else
- texture->initWithImage(pImage);
- #endif
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //使用纹理和图片信息生成相应的可变纹理
- VolatileTexture::addImageTexture(texture,filename,pImageInfo->imageType);
- #endif
- //使用文件名做为查询关键字将纹理存入字典
- m_pTextures->setObject(texture,filename);
- texture->autorelease();
- //调用通知目标的相应函数。
- if(target&&selector)
- {
- (target->*selector)(texture);
- target->release();
- }
- //释放CCImage对象。
- pImage->release();
- //释放new出来的消息结构和图片信息结构。
- deletepAsyncStruct;
- deletepImageInfo;
- //多线程加载引用计数器减1,
- --s_nAsyncRefCount;
- if(0==s_nAsyncRefCount)
- {
- //从显示设备上的回调函数处理器中移除加载回调函数。
- CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack),this);
- }
- }
- }
- //加载一个图片生成纹理。
- CCTexture2D*CCTextureCache::addImage(constchar*path)
- {
- //参数有效性判断
- CCAssert(path!=NULL,"TextureCache:fileimageMUSTnotbeNULL");
- //定义纹理指针变量并置空
- CCTexture2D*texture=NULL;
- //非多线程,故屏蔽,如果addImageAsync在其它线程调用此函数,则打开这段代码。
- //pthread_mutex_lock(m_pDictLock);
- //创建字符串pathKey做为字典查询关键字。
- std::stringpathKey=path;
- //取得图片所在位置的全路径名
- pathKey=CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(pathKey.c_str());
- //用pathKey查询字典中是否有此纹理。
- texture=(CCTexture2D*)m_pTextures->objectForKey(pathKey.c_str());
- //新建字符串fullpath存储全路径。
- std::stringfullpath=pathKey;
- //如果没有找到,
- if(!texture)
- {
- //将文件路径放入新字符串lowerCase。并将字符串中的所有字母转为小写。
- std::stringlowerCase(path);
- for(unsignedinti=0;i<lowerCase.length();++i)
- {
- lowerCase[i]=tolower(lowerCase[i]);
- }
- //
- do
- {
- //如果字符串能够找到".pvr",则代表是pvr文件。调用相应函数将其载入。
- if(std::string::npos!=lowerCase.find(".pvr"))
- {
- texture=this->addPVRImage(fullpath.c_str());
- }
- else
- {
- //否则分别取得文件的格式。
- CCImage::EImageFormateImageFormat=CCImage::kFmtUnKnown;
- if(std::string::npos!=lowerCase.find(".png"))
- {
- eImageFormat=CCImage::kFmtPng;
- }
- elseif(std::string::npos!=lowerCase.find(".jpg")||std::string::npos!=lowerCase.find(".jpeg"))
- {
- eImageFormat=CCImage::kFmtJpg;
- }
- elseif(std::string::npos!=lowerCase.find(".tif")||std::string::npos!=lowerCase.find(".tiff"))
- {
- eImageFormat=CCImage::kFmtTiff;
- }
- //创建CCImage对象,从文件中读取文件的数据并初始化CCImage对象。
- CCImageimage;
- //取得文件大小
- unsignedlongnSize=0;
- //读入数据返回给BYTE类型指针。
- unsignedchar*pBuffer=CCFileUtils::sharedFileUtils()->getFileData(fullpath.c_str(),"rb",&nSize);
- //使用读入的数据初始化相应的图片对象。
- CC_BREAK_IF(!image.initWithImageData((void*)pBuffer,nSize,eImageFormat));
- //读完后释放数据占用的内存。
- CC_SAFE_DELETE_ARRAY(pBuffer);
- //创建一个纹理。
- texture=newCCTexture2D();
- //使用图片对象创建纹理。
- if(texture&&
- texture->initWithImage(&image))
- {
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //使用图片对象生成可变纹理
- VolatileTexture::addImageTexture(texture,fullpath.c_str(),eImageFormat);
- #endif
- //利用路径名做为查询关键字将纹理存入字典。
- m_pTextures->setObject(texture,pathKey.c_str());
- //计数器减1。则刚存入字典的纹理的引用计数器值标记为尚未使用。
- texture->release();
- }
- else
- {
- //失败则打印错误。
- CCLOG("cocos2d:Couldn'taddimage:%sinCCTextureCache",path);
- }
- }
- }while(0);
- }
- //与上面屏蔽加锁一样,这里屏蔽解锁。
- //pthread_mutex_unlock(m_pDictLock);
- returntexture;
- }
- //如果支持PVR的压缩格式。
- #ifdefCC_SUPPORT_PVRTC
- //加载一个PVR的压缩格式的图片。
- CCTexture2D*CCTextureCache::addPVRTCImage(constchar*path,intwidth)
- {
- //参数有效性判断
- CCAssert(path!=NULL,"TextureCache:fileimageMUSTnotbenill");
- //压缩类型参数有效性判断,只能为2或4
- CCAssert(bpp==2||bpp==4,"TextureCache:bppmustbeeither2or4");
- //定义一个新的纹理指针
- CCTexture2D*texture;
- //定义临时字符串存储相对路径名。
- std::stringtemp(path);
- //查询字典中是否已经有此纹理。有则取得并直接返回纹理。
- if((texture=(CCTexture2D*)m_pTextures->objectForKey(temp.c_str())))
- {
- returntexture;
- }
- //取得文件的全路径字符串。
- std::stringfullpath(CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(path));
- //新建变量nLeng用于存储读取到的数据大小。初始化为0。
- unsignedlongnLen=0;
- //新建字符指针pData用于存储读取到的数据并实际读取文件数据。
- unsignedchar*pData=CCFileUtils::sharedFileUtils()->getFileData(fullpath.c_str(),&nLen);
- //新建创一个纹理。
- texture=newCCTexture2D();
- //使用读取到的数据创建纹理。
- if(texture->initWithPVRTCData(pData,bpp,hasAlpha,
- (bpp==2?kCCTexture2DPixelFormat_PVRTC2:kCCTexture2DPixelFormat_PVRTC4)))
- {
- //将纹理以文件名做为关键字存入字典。
- m_pTextures->setObject(texture,temp.c_str());
- //将纹理交由内存管理器处理。
- texture->autorelease();
- }
- else
- {
- //如果创建失败或读取PVR文件失败,打印错误日志。\
- CCLOG("cocos2d:Couldn'taddPVRTCImage:%sinCCTextureCache",path);
- }
- //释放读取文件的数据所占用的内存。
- CC_SAFE_DELETE_ARRAY(pData);
- returntexture;
- }
- #endif//CC_SUPPORT_PVRTC
- //加载一个普通的PVR图片文件
- CCTexture2D*CCTextureCache::addPVRImage(constchar*path)
- {
- //文件名参数有效性判断。
- CCAssert(path!=NULL,"TextureCache:fileimageMUSTnotbenill");
- //新建纹理指针变量置空。
- CCTexture2D*texture=NULL;
- //定义临时字符串存储相对路径名。
- std::stringkey(path);
- //先使用文件名查询是否字典中已经有此纹理了。如果有直接取得并返回纹理。
- if((texture=(CCTexture2D*)m_pTextures->objectForKey(key.c_str())))
- {
- returntexture;
- }
- //由文件名字符串取得图片的全路径字符串。
- std::stringfullpath=CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(key.c_str());
- //动态创建一个纹理。
- texture=newCCTexture2D();
- //如果创建成功,则读取相应的PVR文件来初始化纹理。
- if(texture!=NULL&&texture->initWithPVRFile(fullpath.c_str()))
- {
- //初始化成功。
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //使用纹理和图片信息生成可变纹理。
- VolatileTexture::addImageTexture(texture,CCImage::kFmtRawData);
- #endif
- //将纹理以文件名做为查询关键字存入字典。
- m_pTextures->setObject(texture,key.c_str());
- texture->autorelease();
- }
- else
- {
- //如果创建失败或读取PVR文件失败,打印错误日志。
- CCLOG("cocos2d:Couldn'taddPVRImage:%sinCCTextureCache",key.c_str());
- CC_SAFE_DELETE(texture);
- }
- returntexture;
- }
- //加载一个图片生成纹理,指定参数key做为字典的查询对应关键字。
- CCTexture2D*CCTextureCache::addUIImage(CCImage*image,constchar*key)
- {
- //参数有效性判断
- CCAssert(image!=NULL,"TextureCache:imageMUSTnotbenill");
- //定义纹理指针变量texure做为返回值。这里初始化为空。
- CCTexture2D*texture=NULL;
- //定义字符串变量forKey用来存储完整的图片路径名称。
- std::stringforKey;
- if(key)
- {
- //取得文件名所对应的全路径名,呵呵,这个key也还是个相对路径名啊。
- forKey=CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(key);
- }
- do
- {
- //查询字典是否已经有此纹理了。如果有,取出纹理返回给texture,中断退出。
- if(key&&(texture=(CCTexture2D*)m_pTextures->objectForKey(forKey.c_str())))
- {
- break;
- }
- //动态创建一个纹理对象.返回给texture。
- texture=newCCTexture2D();
- //使用image来初始化纹理.注意:这一句应该移到下面的if中。
- texture->initWithImage(image);
- //初始化完成后以路径名做为查询关键字将纹理存入字典。
- if(key&&texture)
- {
- m_pTextures->setObject(texture,forKey.c_str());
- texture->autorelease();
- }
- else
- {
- //如果key为空或texture为空打印错误
- CCLOG("cocos2d:Couldn'taddUIImageinCCTextureCache");
- }
- }while(0);
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //使用纹理和CCImage对象生成可变纹理。
- VolatileTexture::addCCImage(texture,image);
- #endif
- returntexture;
- }
- //清空字典,释放所有纹理。
- voidCCTextureCache::removeAllTextures()
- {
- m_pTextures->removeAllObjects();
- }
- //清除未被外部使用的纹理
- voidCCTextureCache::removeUnusedTextures()
- {
- /*原来的做法,因为有问题给屏蔽了,仍然解释下:
- //定义字典词汇指针变量pElement。
- CCDictElement*pElement=NULL;
- //遍历字典
- CCDICT_FOREACH(m_pTextures,pElement)
- {
- //打印词汇信息
- CCLOG("cocos2d:CCTextureCache:texture:%s",pElement->getStrKey());
- //取得词汇对应的纹理
- CCTexture2D*value=(CCTexture2D*)pElement->getObject();
- //如果引用计数器值为1,从字典中删除。
- if(value->retainCount()==1)
- {
- CCLOG("cocos2d:CCTextureCache:removingunusedtexture:%s",pElement->getStrKey());
- m_pTextures->removeObjectForElememt(pElement);
- }
- }
- */
- //现在的做法
- //判断字典不为空
- if(m_pTextures->count())
- {
- //定义字典词汇指针变量pElement。
- CCDictElement*pElement=NULL;
- //定义一个list容器用来存储未被外部使用的纹理指针。
- list<CCDictElement*>elementToRemove;
- //遍历字典
- CCDICT_FOREACH(m_pTextures,pElement)
- {
- //打印词汇信息
- CCLOG("cocos2d:CCTextureCache:texture:%s",pElement->getStrKey());
- //取得词汇对应的纹理
- CCTexture2D*value=(CCTexture2D*)pElement->getObject();
- if(value->retainCount()==1)
- {
- //如果引用计数器值为1,先存入容器中。
- elementToRemove.push_back(pElement);
- }
- }
- //遍历list中的元素从字典中删除
- for(list<CCDictElement*>::iteratoriter=elementToRemove.begin();iter!=elementToRemove.end();++iter)
- {
- //打印删除元素日志。
- CCLOG("cocos2d:CCTextureCache:removingunusedtexture:%s",(*iter)->getStrKey());
- //从字典中删除
- m_pTextures->removeObjectForElememt(*iter);
- }
- }
- //好吧,答案是因为CCDICT_FOREACH和removeObjectForElememt会互相影响,CCDICT_FOREACH中会调用HASH_ITER循环遍历。而循环的计数器是位置,通过地址对比来找下一个结点位置。而removeObjectForElememt会调用HASH_DELETE删除元素导致链表的重构。重构后会影响到HASK_ITER的查询。
- }
- //移除一个纹理
- voidCCTextureCache::removeTexture(CCTexture2D*texture)
- {
- //参数有效性判断
- if(!texture)
- {
- return;
- }
- //查询所有对应此纹理的词汇
- CCArray*keys=m_pTextures->allKeysForObject(texture);
- //从字典中把这些词汇及相应纹理删除。
- m_pTextures->removeObjectsForKeys(keys);
- }
- //由字典查询关键字找到相应纹理并移除。
- voidCCTextureCache::removeTextureForKey(constchar*textureKeyName)
- {
- //参数有效性判断
- if(textureKeyName==NULL)
- {
- return;
- }
- //查询关键字实际是文件的相对路径,这里取得全路径。
- stringfullPath=CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(textureKeyName);
- //将全路径做为查询关键字从字典中删除相应词汇及纹理
- m_pTextures->removeObjectForKey(fullPath.c_str());
- }
- //由字典查询关键字找到相应纹理
- CCTexture2D*CCTextureCache::textureForKey(constchar*key)
- {
- return(CCTexture2D*)m_pTextures->objectForKey(CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(key));
- }
- //重新载入所有的纹理
- voidCCTextureCache::reloadAllTextures()
- {
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //调用可变纹理的静态函数重新载入所有的纹理
- VolatileTexture::reloadAllTextures();
- #endif
- }
- //打印字典中的纹理统计信息。
- voidCCTextureCache::dumpCachedTextureInfo()
- {
- unsignedintcount=0;
- unsignedinttotalBytes=0;
- CCDictElement*pElement=NULL;
- //遍历字典中的所有词汇信息
- CCDICT_FOREACH(m_pTextures,pElement)
- {
- //取得词汇对应的纹理
- CCTexture2D*tex=(CCTexture2D*)pElement->getObject();
- //取得纹理对应贴图的色深
- unsignedintbpp=tex->bitsPerPixelForFormat();
- //生成贴图占用的内存大小(字节数量)
- unsignedintbytes=tex->getPixelsWide()*tex->getPixelsHigh()*bpp/8;
- //统计内存总大小
- totalBytes+=bytes;
- count++;
- //打印纹理信息
- CCLOG("cocos2d:\"%s\"rc=%luid=%lu%lux%lu@%ldbpp=>%luKB",
- pElement->getStrKey(),//查询关键字
- (long)tex->retainCount(),//使用次数
- (long)tex->getName(),//图片名称
- (long)tex->getPixelsWide(),//对应贴图的宽度
- (long)tex->getPixelsHigh(),//对应贴图的高度
- (long)bpp,//对应贴图色深
- (long)bytes/1024);//占用内存大小(千字节数量)
- }
- //打印总的数量数量,占用内存数量。
- CCLOG("cocos2d:CCTextureCachedumpDebugInfo:%ldtextures,for%luKB(%.2fMB)",(long)count,(long)totalBytes/1024,totalBytes/(1024.0f*1024.0f));
- }
- //如果开启了使用多变纹理
- #ifCC_ENABLE_CACHE_TEXTURE_DATA
- //定义全局的list容器,用来存储产生的多变纹理对象指针
- std::list<VolatileTexture*>VolatileTexture::textures;
- //定义布尔变量标记是否在全部重新载入
- boolVolatileTexture::isReloading=false;
- //构造函数
- VolatileTexture::VolatileTexture(CCTexture2D*t)
- :texture(t)
- ,m_eCashedImageType(kInvalid)
- ,m_pTextureData(NULL)
- ,m_PixelFormat(kTexture2DPixelFormat_RGBA8888)
- ,m_strFileName("")
- ,m_FmtImage(CCImage::kFmtPng)
- ,m_alignment(kCCTextAlignmentCenter)
- ,m_vAlignment(kCCVerticalTextAlignmentCenter)
- ,m_strFontName("")
- ,m_strText("")
- ,uiImage(NULL)
- ,m_fFontSize(0.0f)
- {
- m_size=CCSizeMake(0,0);
- textures.push_back(this);
- }
- //析构函数
- VolatileTexture::~VolatileTexture()
- {
- textures.remove(this);
- CC_SAFE_RELEASE(uiImage);
- }
- //通过纹理图片属性信息生成可变纹理。
- voidVolatileTexture::addImageTexture(CCTexture2D*tt,CCImage::EImageFormatformat)
- {
- //如果正在重新载入过程中,直接返回。
- if(isReloading)
- {
- return;
- }
- //通过纹理指针找到相应的可变纹理,如果没有则new一个返回其指针。
- VolatileTexture*vt=findVolotileTexture(tt);
- //设置相关属性,注意:这里最好对vt做下有效性检查,如果为NULL的话会崩溃的。
- vt->m_eCashedImageType=kImageFile;
- vt->m_strFileName=imageFileName;
- vt->m_FmtImage=format;
- vt->m_PixelFormat=tt->getPixelFormat();
- }
- //通过CCImage对象生成可变纹理。
- voidVolatileTexture::addCCImage(CCTexture2D*tt,CCImage*image)
- {
- //通过纹理指针找到相应的可变纹理,如果没有则new一个返回其指针。
- VolatileTexture*vt=findVolotileTexture(tt);
- image->retain();
- //设置相关属性
- vt->uiImage=image;
- vt->m_eCashedImageType=kImage;
- }
- //通过纹理指针找到相应的可变纹理,如果没有则new出一个返回。
- VolatileTexture*VolatileTexture::findVolotileTexture(CCTexture2D*tt)
- {
- VolatileTexture*vt=0;
- //遍历list容器,对比查询。
- std::list<VolatileTexture*>::iteratori=textures.begin();
- while(i!=textures.end())
- {
- VolatileTexture*v=*i++;
- if(v->texture==tt)
- {
- vt=v;
- break;
- }
- }
- //如果没有找到,则由纹理参数new出一个可变纹理,new会调用其带参数的拷贝构造函数设置其对应纹理。
- if(!vt)
- {
- vt=newVolatileTexture(tt);
- }
- returnvt;
- }
- //通过指定图像数据,像素格式和图片大小来生成可变纹理。
- voidVolatileTexture::addDataTexture(CCTexture2D*tt,constCCSize&contentSize)
- {
- //如果正在重新载入过程中,直接返回。
- if(isReloading)
- {
- return;
- }
- //通过纹理指针找到相应的可变纹理,如果没有则new一个返回其指针。
- VolatileTexture*vt=findVolotileTexture(tt);
- //设置相关属性
- vt->m_eCashedImageType=kImageData;
- vt->m_pTextureData=data;
- vt->m_PixelFormat=pixelFormat;
- vt->m_TextureSize=contentSize;
- }
- //由字符串和相应信息生成可变纹理
- voidVolatileTexture::addStringTexture(CCTexture2D*tt,floatfontSize)
- {
- //如果正在重新载入过程中,直接返回。
- if(isReloading)
- {
- return;
- }
- //通过纹理指针找到相应的可变纹理,如果没有则new一个返回其指针。
- VolatileTexture*vt=findVolotileTexture(tt);
- //设置相关属性
- vt->m_eCashedImageType=kString;
- vt->m_size=dimensions;
- vt->m_strFontName=fontName;
- vt->m_alignment=alignment;
- vt->m_vAlignment=vAlignment;
- vt->m_fFontSize=fontSize;
- vt->m_strText=text;
- }
- //通过纹理指针找到相应的可变纹理并删除。
- voidVolatileTexture::removeTexture(CCTexture2D*t)
- {
- std::list<VolatileTexture*>::iteratori=textures.begin();
- while(i!=textures.end())
- {
- VolatileTexture*vt=*i++;
- if(vt->texture==t)
- {
- deletevt;
- break;
- }
- }
- }
- //重新载入所有的纹理。
- voidVolatileTexture::reloadAllTextures()
- {
- //设置开始进行重新载入所有纹理。
- isReloading=true;
- CCLOG("reloadalltexture");
- //通过迭代器遍历list容器
- std::list<VolatileTexture*>::iteratoriter=textures.begin();
- while(iter!=textures.end())
- {
- VolatileTexture*vt=*iter++;
- //根据不同的格式进行纹理的重建
- switch(vt->m_eCashedImageType)
- {
- casekImageFile:
- {
- //这里定义一个CCImage对象image
- CCImageimage;
- //先将路径名都变成小写字符串。
- std::stringlowerCase(vt->m_strFileName.c_str());
- for(unsignedinti=0;i<lowerCase.length();++i)
- {
- lowerCase[i]=tolower(lowerCase[i]);
- }
- //扩展名对比,如果是PVR文件
- if(std::string::npos!=lowerCase.find(".pvr"))
- {
- //取得原来的默认带ALPHA通道的像素格式。
- CCTexture2DPixelFormatoldPixelFormat=CCTexture2D::defaultAlphaPixelFormat();
- //重设默认带ALPHA通道的像素格式。
- CCTexture2D::setDefaultAlphaPixelFormat(vt->m_PixelFormat);
- //纹理重新由PVR文件进行初始化。会用到新的默认带ALPHA通道的像素格式。
- vt->texture->initWithPVRFile(vt->m_strFileName.c_str());
- //重设原来的默认带ALPHA通道的像素格式。
- CCTexture2D::setDefaultAlphaPixelFormat(oldPixelFormat);
- }
- else
- {
- //如果是非PVR文件。
- unsignedlongnSize=0;
- //通过文件工具集中的接口读入图片文件并返回数据地址。
- unsignedchar*pBuffer=CCFileUtils::sharedFileUtils()->getFileData(vt->m_strFileName.c_str(),&nSize);
- //使用数据地址对前面定义的CCImage对象image进行初始化。
- if(image.initWithImageData((void*)pBuffer,vt->m_FmtImage))
- {
- //取得原来的默认带ALPHA通道的像素格式。
- CCTexture2DPixelFormatoldPixelFormat=CCTexture2D::defaultAlphaPixelFormat();
- //重设默认带ALPHA通道的像素格式。CCTexture2D::setDefaultAlphaPixelFormat(vt->m_PixelFormat);
- //纹理重新由图片对象初始化。会用到新的默认带ALPHA通道的像素格式。
- vt->texture->initWithImage(&image);
- //重设原来的默认带ALPHA通道的像素格式。
- CCTexture2D::setDefaultAlphaPixelFormat(oldPixelFormat);
- }
- CC_SAFE_DELETE_ARRAY(pBuffer);
- }
- }
- break;
- casekImageData:
- {
- //纹理重新由图片数据初始化。
- vt->texture->initWithData(vt->m_pTextureData,
- vt->m_PixelFormat,
- vt->m_TextureSize.width,
- vt->m_TextureSize.height,
- vt->m_TextureSize);
- }
- break;
- casekString:
- {
- //纹理重新由字符串初始化。
- vt->texture->initWithString(vt->m_strText.c_str(),
- vt->m_size,
- vt->m_alignment,
- vt->m_vAlignment,
- vt->m_strFontName.c_str(),
- vt->m_fFontSize);
- }
- break;
- casekImage:
- {
- //纹理重新由图片对象初始化。
- vt->texture->initWithImage(vt->uiImage);
- }
- break;
- default:
- break;
- }
- }
- //设置重新载入完成
- isReloading=false;
- }
- #endif//CC_ENABLE_CACHE_TEXTURE_DATA
- NS_CC_END
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。