cocos2d-x 源码剖析(16)
2014-03-10 14:33
337 查看
上一节讲了CCImage,这节讲CCTexture。毕竟我们就是从CCTexture讲岔到CCImage的。CCTexture负责纹理的加载和维护。他的函数分为三部分:
初始化函数
加载函数
管理函数
我们先来看加载函数,这是CCTexture的根本所在:
对于那些OpenGL函数是做什么用的,我就不多做介绍了。不明真相的同学可以参考相关资料。这里要注意的是那个m_uName,他是由OpenGL分配的,也是Texture的索引。我们可以注意到,OpenGL是支持相当多的格式的,根据自身的情况选择合适的格式才是王道。如果你要开发一款像素风格的游戏,还要采用RGBA8888的话,我只能说你很有想法了。
下面来看初始化函数:
先来讲讲从CCImage来加载纹理。我们通过不同的图片来解压,得到的其实是一个RGBA8888的位图(Bitmap)格式。这个格式是很占用内存的,在initWithImage的内部调用了initPremultipliedATextureWithImage(uiImage, imageWidth, imageHeight);这个函数来将ARGB8888格式转化为我们预设的格式,当然默认情况下是RGBA8888的。这个函数是一个很好的位图格式转化示例,有需求的朋友可以参考下。格式可以由下面的函数来设置:
这是一个静态变量,使用的时候需要注意:
我们还可以从一个String初始化一个纹理。还记得我们能从一个String初始化一个CCImage吗?没错,CCTexutre就是先将用String初始化一个CCImage,再调用上面的方法由CCImage初始化的。
最后我们来看看从纹理格式初始化,ETC和PVR个过程极其类似,我们利用PVR进行讲解看其函数:
我们看到,它将一些工作交给CCTexturePVR来做,我们只要注意的是那个m_uName就可以了,有了这个索引,我们就能从OpenGL中绑定指定的纹理来进行绘制。它的载入工作也是类似的,不过有一段代码比较有意思:
注意那个if语句中的函数调用,最后那个函数便是将数据导入到OpenGL中去。具体代码我就不贴了。从CCTexture的导入中我们可以看到,如果使用PVR或者ECT格式的话,加载过程和速度都要比使用图片方便快捷。唯一的不便在于这两种格式的体积略大。
看到这里,我想大家对于cocos2d-x如何加载纹理有了清晰的了解。我最好还有强调一点,就是那个m_uName,它是OpenGL中的纹理索引,而且是一个GLunit类型的。之后我们将会看到是如何管理和使用这个索引的。
最后我们来看看纹理的删除:
与加载过程相比,删除过程真是简单粗暴啊。CCTexture是OpenGL中纹理的呈现,里面还有一些管理函数,都比较简单。有兴趣的可以查看。还有一个有意思的东西就是Premultiplied alpha,如果你使用纹理格式,一定要注意这个属性。对其原理,请Google之。
初始化函数
加载函数
管理函数
我们先来看加载函数,这是CCTexture的根本所在:
bool CCTexture2D::initWithData(const void *data, CCTexture2DPixelFormat pixelFormat, unsigned int pixelsWide, unsigned int pixelsHigh, const CCSize& contentSize) { unsigned int bitsPerPixel; //Hack: bitsPerPixelForFormat returns wrong number for RGB_888 textures. See function. if(pixelFormat == kCCTexture2DPixelFormat_RGB888) { bitsPerPixel = 24; } else { bitsPerPixel = bitsPerPixelForFormat(pixelFormat); } unsigned int bytesPerRow = pixelsWide * bitsPerPixel / 8; if(bytesPerRow % 8 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 8); } else if(bytesPerRow % 4 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else if(bytesPerRow % 2 == 0) { glPixelStorei(GL_UNPACK_ALIGNMENT, 2); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } glGenTextures(1, &m_uName); ccGLBindTexture2D(m_uName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); // Specify OpenGL texture image switch(pixelFormat) { case kCCTexture2DPixelFormat_RGBA8888: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGB888: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGBA4444: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); break; case kCCTexture2DPixelFormat_RGB5A1: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); break; case kCCTexture2DPixelFormat_RGB565: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); break; case kCCTexture2DPixelFormat_AI88: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_I8: glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); break; default: CCAssert(0, "NSInternalInconsistencyException"); } m_tContentSize = contentSize; m_uPixelsWide = pixelsWide; m_uPixelsHigh = pixelsHigh; m_ePixelFormat = pixelFormat; m_fMaxS = contentSize.width / (float)(pixelsWide); m_fMaxT = contentSize.height / (float)(pixelsHigh); m_bHasPremultipliedAlpha = false; m_bHasMipmaps = false; setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture)); return true; }
对于那些OpenGL函数是做什么用的,我就不多做介绍了。不明真相的同学可以参考相关资料。这里要注意的是那个m_uName,他是由OpenGL分配的,也是Texture的索引。我们可以注意到,OpenGL是支持相当多的格式的,根据自身的情况选择合适的格式才是王道。如果你要开发一款像素风格的游戏,还要采用RGBA8888的话,我只能说你很有想法了。
下面来看初始化函数:
bool initWithImage(CCImage* uiImage); /** Initializes a texture from a string with dimensions, alignment, font name and font size */ bool initWithString(const char*text, const char*fontName,float fontSize,const CCSize &dimensions,CCTextAlignmenth Alignment,CCVerticalTextAlignmentv Alignment); /** Initializes a texture from a string with font name and font size */ bool initWithString(const char*text,cons tchar*fontName,float fontSize); /** Initializes a texture from a string using a text definition*/ bool initWithString(const char*text,ccFontDefinition* textDefinition); /** Initializes a texture from a PVR file */ bool initWithPVRFile(const char*file); /** Initializes a texture from a ETC file */ bool initWithETCFile(const char*file);
先来讲讲从CCImage来加载纹理。我们通过不同的图片来解压,得到的其实是一个RGBA8888的位图(Bitmap)格式。这个格式是很占用内存的,在initWithImage的内部调用了initPremultipliedATextureWithImage(uiImage, imageWidth, imageHeight);这个函数来将ARGB8888格式转化为我们预设的格式,当然默认情况下是RGBA8888的。这个函数是一个很好的位图格式转化示例,有需求的朋友可以参考下。格式可以由下面的函数来设置:
void CCTexture2D::setDefaultAlphaPixelFormat(CCTexture2DPixelFormat format) { g_defaultAlphaPixelFormat=format; } CCTexture2DPixelFormat CCTexture2D::defaultAlphaPixelFormat() { return g_defaultAlphaPixelFormat; }
这是一个静态变量,使用的时候需要注意:
// If the image has alpha, you can create RGBA8 (32-bit) or RGBA4 (16-bit) or RGB5A1 (16-bit) // Default is: RGBA8888 (32-bit textures) static CCTexture2DPixelFormat g_defaultAlphaPixelFormat = kCCTexture2DPixelFormat_Default;
我们还可以从一个String初始化一个纹理。还记得我们能从一个String初始化一个CCImage吗?没错,CCTexutre就是先将用String初始化一个CCImage,再调用上面的方法由CCImage初始化的。
最后我们来看看从纹理格式初始化,ETC和PVR个过程极其类似,我们利用PVR进行讲解看其函数:
bool CCTexture2D::initWithPVRFile(const char* file) { bool bRet=false; // nothing to do with CCObject::init CCTexturePVR* pvr = new CCTexturePVR; bRet = pvr->initWithContentsOfFile(file); if(bRet) { pvr->setRetainName(true);// don't dealloc texture on release 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't load PVR image %s",file); } return bRet; }
我们看到,它将一些工作交给CCTexturePVR来做,我们只要注意的是那个m_uName就可以了,有了这个索引,我们就能从OpenGL中绑定指定的纹理来进行绘制。它的载入工作也是类似的,不过有一段代码比较有意思:
if(!((unpackPVRv2Data(pvrdata,pvrlen) ||unpackPVRv3Data(pvrdata,pvrlen))&&createGLTexture())) { CC_SAFE_DELETE_ARRAY(pvrdata); this->release(); return false; }
注意那个if语句中的函数调用,最后那个函数便是将数据导入到OpenGL中去。具体代码我就不贴了。从CCTexture的导入中我们可以看到,如果使用PVR或者ECT格式的话,加载过程和速度都要比使用图片方便快捷。唯一的不便在于这两种格式的体积略大。
看到这里,我想大家对于cocos2d-x如何加载纹理有了清晰的了解。我最好还有强调一点,就是那个m_uName,它是OpenGL中的纹理索引,而且是一个GLunit类型的。之后我们将会看到是如何管理和使用这个索引的。
CC_PROPERTY_READONLY(GLuint,m_uName,Name)
最后我们来看看纹理的删除:
CCTexture2D::~CCTexture2D() { #if CC_ENABLE_CACHE_TEXTURE_DATA VolatileTexture::removeTexture(this); #endif CCLOGINFO("cocos2d: deallocing CCTexture2D %u.",m_uName); CC_SAFE_RELEASE(m_pShaderProgram); if(m_uName) { ccGLDeleteTexture(m_uName); } }
void ccGLDeleteTexture(GLuint textureId) { ccGLDeleteTextureN(0,textureId); } void ccGLDeleteTextureN(GLuint textureUnit,GLuint textureId) { #if CC_ENABLE_GL_STATE_CACHE if(s_uCurrentBoundTexture[textureUnit]==textureId) { s_uCurrentBoundTexture[textureUnit]=-1; } #endif // CC_ENABLE_GL_STATE_CACHE glDeleteTextures(1,&textureId); }
与加载过程相比,删除过程真是简单粗暴啊。CCTexture是OpenGL中纹理的呈现,里面还有一些管理函数,都比较简单。有兴趣的可以查看。还有一个有意思的东西就是Premultiplied alpha,如果你使用纹理格式,一定要注意这个属性。对其原理,请Google之。
相关文章推荐
- cocos2d-x 源码剖析(17)
- cocos2d-x 源码剖析(18)
- cocos2d-x 源码剖析(19)
- cocos2d-x应用窗口相关源码剖析1
- cocos2d-x 源码剖析(20)
- cocos2d-x源码剖析引子
- cocos2d-x 源码剖析(1)
- cocos2d-x 源码剖析(21)
- cocos2d-x源码剖析之场景管理
- cocos2d-x应用窗口相关源码剖析2
- cocos2d-x 源码剖析(2)
- bombing:cocos2d-x应用窗口相关源码剖析3
- cocos2d-x 源码剖析(7)
- cocos2d-x应用窗口相关源码剖析4
- cocos2d-x 源码剖析(3)
- cocos2d-x 源码剖析(8)
- 知识图谱实战开发案例剖析(16)-第一个智能对话机器人(附完整源码)
- cocos2d-x源码剖析之精灵对象
- cocos2d-x 源码剖析(4)
- cocos2d-x 源码剖析(9)