CCSprite类的东西非常多,只能一部分一部分的分析和学习。
CONTENTS
各种创建方法,最终还是调用了initWithTexture 方法。
CCSprite* CCSprite::createWithTexture(CCTexture2D *pTexture) { 。。。。。//==>>直接调用initWithTexture if (pobSprite && pobSprite->initWithTexture(pTexture)) 。。。。。 } CCSprite* CCSprite::createWithTexture(CCTexture2D *pTexture, const CCRect& rect) { 。。。。。//==>>直接调用initWithTexture if (pobSprite && pobSprite->initWithTexture(pTexture, rect)) 。。。。。 } CCSprite* CCSprite::create(const char *pszFileName) { 。。。。。//==>>调用initWithFile,间接调用initWithTexture if (pobSprite && pobSprite->initWithFile(pszFileName)) 。。。。。 } CCSprite* CCSprite::create(const char *pszFileName, const CCRect& rect) { 。。。。。//==>>调用initWithFile,间接调用initWithTexture if (pobSprite && pobSprite->initWithFile(pszFileName, rect)) 。。。。。 } CCSprite* CCSprite::createWithSpriteFrame(CCSpriteFrame *pSpriteFrame) { 。。。。。//==>>调用initWithSpriteFrame,间接调用initWithTexture if (pSpriteFrame && pobSprite && pobSprite->initWithSpriteFrame(pSpriteFrame)) 。。。。。 } CCSprite* CCSprite::createWithSpriteFrameName(const char *pszSpriteFrameName) { 。。。。。//==>>调用createWithSpriteFrame,间接调用initWithTexture return createWithSpriteFrame(pFrame); } CCSprite* CCSprite::create() { 。。。。。//==>>调用init,间接调用initWithTexture if (pSprite && pSprite->init()) 。。。。。 } bool CCSprite::init(void) { 。。。。。//==>>init方法内部调用initWithTexture return initWithTexture(NULL, CCRectZero); } bool CCSprite::initWithTexture(CCTexture2D *pTexture, const CCRect& rect) { 。。。。。//==>>调用initWithTexture,不旋转 return initWithTexture(pTexture, rect, false); } bool CCSprite::initWithTexture(CCTexture2D *pTexture) { 。。。。。//==>>调用initWithTexture,大小为texture的大小 return initWithTexture(pTexture, rect); } bool CCSprite::initWithFile(const char *pszFilename) { 。。。。。//==>>先把文件读入到texturecache的缓存中去,然后调用initWithTexture CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFilename); if (pTexture) { CCRect rect = CCRectZero; rect.size = pTexture->getContentSize(); return initWithTexture(pTexture, rect); 。。。。。 } bool CCSprite::initWithFile(const char *pszFilename, const CCRect& rect) { 。。。。。//==>>先把文件读入到texturecache的缓存中去,然后调用initWithTexture CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFilename); if (pTexture) { return initWithTexture(pTexture, rect); 。。。。。 } bool CCSprite::initWithSpriteFrame(CCSpriteFrame *pSpriteFrame) { CCAssert(pSpriteFrame != NULL, ""); //==>>从精灵帧中取出texture,然后调用initWithTexture bool bRet = initWithTexture(pSpriteFrame->getTexture(), pSpriteFrame->getRect()); setDisplayFrame(pSpriteFrame); return bRet; } bool CCSprite::initWithSpriteFrameName(const char *pszSpriteFrameName) { 。。。。。//==>>从精灵帧缓存中取出精灵帧,然后调用initWithSpriteFrame CCSpriteFrame *pFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(pszSpriteFrameName); return initWithSpriteFrame(pFrame); }
initWithTexture代码分析
bool CCSprite::initWithTexture(CCTexture2D *pTexture, const CCRect& rect, bool rotated) { if (CCNodeRGBA::init()) { m_pobBatchNode = NULL;//==>>不使用批量创建node方法 //==>>m_bRecursiveDirty: Whether all of the sprite's children needs to be updated m_bRecursiveDirty = false;//==>>级联置脏为false setDirty(false);//==>>设置m_bDirty为false m_bOpacityModifyRGB = true;//==>>CCSprite继承自CCNodeRGBA,因此设置该属性为true m_sBlendFunc.src = CC_BLEND_SRC;//==>>设置混合模式 m_sBlendFunc.dst = CC_BLEND_DST; m_bFlipX = m_bFlipY = false; //==>>x,y均不翻转 // default transform anchor: center setAnchorPoint(ccp(0.5f, 0.5f));//==>>设置锚点 // zwoptex default values m_obOffsetPosition = CCPointZero;//==>>偏移量,默认为0,0 m_bHasChildren = false;//==>>初始化时没有子节点 // clean the Quad memset(&m_sQuad, 0, sizeof(m_sQuad));//==>>初始化时正方形纹理4个角的信息都为0 // Atlas: Color ccColor4B tmpColor = { 255, 255, 255, 255 };//==>>初始化时设置正方形纹理4个角的颜色信息 m_sQuad.bl.colors = tmpColor; m_sQuad.br.colors = tmpColor; m_sQuad.tl.colors = tmpColor; m_sQuad.tr.colors = tmpColor; // shader program //==>>设置shader setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor)); // update texture (calls updateBlendFunc) setTexture(pTexture); setTextureRect(rect, rotated, rect.size); // by default use "Self Render". // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" setBatchNode(NULL); return true; } else { return false; } }
setTexture代码分析
void CCSprite::setTexture(CCTexture2D *texture) { //==>>正确性判断, // If batchnode, then texture id should be the same CCAssert(! m_pobBatchNode || texture->getName() == m_pobBatchNode->getTexture()->getName(), "CCSprite: Batched sprites should use the same texture as the batchnode"); // accept texture==nil as argument CCAssert( !texture || dynamic_cast<CCTexture2D*>(texture), "setTexture expects a CCTexture2D. Invalid argument"); //==>>如果texture为NULL 就找一个默认的。 if (NULL == texture) { // Gets the texture by key firstly. texture = CCTextureCache::sharedTextureCache()->textureForKey(CC_2x2_WHITE_IMAGE_KEY); // If texture wasn't in cache, create it from RAW data. if (NULL == texture) { CCImage* image = new CCImage(); bool isOK = image->initWithImageData(cc_2x2_white_image, sizeof(cc_2x2_white_image), CCImage::kFmtRawData, 2, 2, 8); CCAssert(isOK, "The 2x2 empty texture was created unsuccessfully."); texture = CCTextureCache::sharedTextureCache()->addUIImage(image, CC_2x2_WHITE_IMAGE_KEY); CC_SAFE_RELEASE(image); } } //==>>如果m_pobBatchNode为NULL,并且texture和之前存放的不同,那么就更新下。 if (!m_pobBatchNode && m_pobTexture != texture) { CC_SAFE_RETAIN(texture); CC_SAFE_RELEASE(m_pobTexture); m_pobTexture = texture; updateBlendFunc(); } } //更新混合模式。 void CCSprite::updateBlendFunc(void) { CCAssert (! m_pobBatchNode, "CCSprite: updateBlendFunc doesn't work when the sprite is rendered using a CCSpriteBatchNode"); // it is possible to have an untextured sprite if (! m_pobTexture || ! m_pobTexture->hasPremultipliedAlpha()) { m_sBlendFunc.src = GL_SRC_ALPHA; m_sBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; setOpacityModifyRGB(false); } else { m_sBlendFunc.src = CC_BLEND_SRC; m_sBlendFunc.dst = CC_BLEND_DST; setOpacityModifyRGB(true); } } //==>>设置RGB模式 void CCSprite::setOpacityModifyRGB(bool modify) { if (m_bOpacityModifyRGB != modify) { m_bOpacityModifyRGB = modify; updateColor(); } } //==>>更新颜色 void CCSprite::updateColor(void) { ccColor4B color4 = { _displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity }; // special opacity for premultiplied textures if (m_bOpacityModifyRGB) { color4.r *= _displayedOpacity/255.0f; color4.g *= _displayedOpacity/255.0f; color4.b *= _displayedOpacity/255.0f; } //==>>更新正方形4个角的颜色值 m_sQuad.bl.colors = color4; m_sQuad.br.colors = color4; m_sQuad.tl.colors = color4; m_sQuad.tr.colors = color4; // renders using batch node if (m_pobBatchNode) { if (m_uAtlasIndex != CCSpriteIndexNotInitialized) { m_pobTextureAtlas->updateQuad(&m_sQuad, m_uAtlasIndex); } else { // no need to set it recursively // update dirty_, don't update recursiveDirty_ setDirty(true); } } // self render // do nothing }
setTextureRect代码分析
void CCSprite::setTextureRect(const CCRect& rect, bool rotated, const CCSize& untrimmedSize) { m_bRectRotated = rotated;//==>>设置是否旋转 //==>>设置大小,设置顶点矩阵大小,计算纹理坐标 setContentSize(untrimmedSize); setVertexRect(rect); setTextureCoords(rect); CCPoint relativeOffset = m_obUnflippedOffsetPositionFromCenter; // issue #732 if (m_bFlipX) { relativeOffset.x = -relativeOffset.x; } if (m_bFlipY) { relativeOffset.y = -relativeOffset.y; } m_obOffsetPosition.x = relativeOffset.x + (m_obContentSize.width - m_obRect.size.width) / 2; m_obOffsetPosition.y = relativeOffset.y + (m_obContentSize.height - m_obRect.size.height) / 2; // rendering using batch node if (m_pobBatchNode) { // update dirty_, don't update recursiveDirty_ setDirty(true); } else { // self rendering // Atlas: Vertex float x1 = 0 + m_obOffsetPosition.x; float y1 = 0 + m_obOffsetPosition.y; float x2 = x1 + m_obRect.size.width; float y2 = y1 + m_obRect.size.height; //==>>设置正方形顶点坐标 // Don't update Z. m_sQuad.bl.vertices = vertex3(x1, y1, 0); m_sQuad.br.vertices = vertex3(x2, y1, 0); m_sQuad.tl.vertices = vertex3(x1, y2, 0); m_sQuad.tr.vertices = vertex3(x2, y2, 0); } } void CCNode::setContentSize(const CCSize & size) { //==>>如果大小没变,就直接返回。如果变了,就更新下大小,然后根据锚点比例,重新计算锚点的实际位置,将dirty置true。 if ( ! size.equals(m_obContentSize)) { m_obContentSize = size; //==>>m_obAnchorPoint就是我们经常在程序中设置的锚点比例。 //==>>m_obAnchorPointInPoints是实际的锚点位置 m_obAnchorPointInPoints = ccp(m_obContentSize.width * m_obAnchorPoint.x, m_obContentSize.height * m_obAnchorPoint.y ); m_bTransformDirty = m_bInverseDirty = true; } } /** * Sets the vertex rect. * It will be called internally by setTextureRect. * Useful if you want to create 2x images from SD images in Retina Display. * Do not call it manually. Use setTextureRect instead. */ void CCSprite::setVertexRect(const CCRect& rect) {//==>>设置顶点矩阵的大小 m_obRect = rect; } //==>>根据纹理的大小和sprite的大小设置纹理坐标 void CCSprite::setTextureCoords(CCRect rect) { //==>>首先将sprite的大小转换为像素大小 rect = CC_RECT_POINTS_TO_PIXELS(rect); //==>>获取纹理,并且获取纹理的像素宽,像素高 CCTexture2D *tex = m_pobBatchNode ? m_pobTextureAtlas->getTexture() : m_pobTexture; if (! tex) { return; } float atlasWidth = (float)tex->getPixelsWide(); float atlasHeight = (float)tex->getPixelsHigh(); float left, right, top, bottom; if (m_bRectRotated) { 。。。。。 //==>>旋转后的纹理坐标设置,和不旋转的代码差不多,只是坐标点是反的。 。。。。。 } else { #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL left = (2*rect.origin.x+1)/(2*atlasWidth); right = left + (rect.size.width*2-2)/(2*atlasWidth); top = (2*rect.origin.y+1)/(2*atlasHeight); bottom = top + (rect.size.height*2-2)/(2*atlasHeight); #else //==>> 根据sprite的像素大小和纹理的像素宽高计算正方形纹理坐标的4个点。 left = rect.origin.x/atlasWidth; right = (rect.origin.x + rect.size.width) / atlasWidth; top = rect.origin.y/atlasHeight; bottom = (rect.origin.y + rect.size.height) / atlasHeight; #endif // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL //==>>如果左右翻转,那么左右点翻转 if(m_bFlipX) { CC_SWAP(left,right,float); } //==>>如果上下翻转,那么上下点翻转 if(m_bFlipY) { CC_SWAP(top,bottom,float); } //==>>将计算好的4个点根据规则设置到正方形纹理的4个角中。 //==>>参考网址【 http://blog.sina.com.cn/s/blog_6d8189930100nfvw.html 】 m_sQuad.bl.texCoords.u = left; m_sQuad.bl.texCoords.v = bottom; m_sQuad.br.texCoords.u = right; m_sQuad.br.texCoords.v = bottom; m_sQuad.tl.texCoords.u = left; m_sQuad.tl.texCoords.v = top; m_sQuad.tr.texCoords.u = right; m_sQuad.tr.texCoords.v = top; } }
更新==》》
draw代码分析
在分析draw方法前,先看先以前的一部分学习记录:
首先是CCSprite使用的shader:
bool CCSprite::initWithTexture(CCTexture2D *pTexture, const CCRect& rect, bool rotated) { 。。。。。 setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor)); 。。。。。 }
我们在回过头来看下kCCUniformSampler中的Shader_PositionTextureColor的有关代码:
void CCShaderCache::loadDefaultShader(CCGLProgram *p, int type) { switch (type) { case kCCShaderType_PositionTextureColor: p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColor_frag); p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position); p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color); p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords); break; 。。。。。 p->updateUniforms(); 。。。。。 }
CCGLProgram中的有关代码:
void CCGLProgram::updateUniforms() { m_uUniforms[kCCUniformPMatrix] = glGetUniformLocation(m_uProgram, kCCUniformPMatrix_s); m_uUniforms[kCCUniformMVMatrix] = glGetUniformLocation(m_uProgram, kCCUniformMVMatrix_s); m_uUniforms[kCCUniformMVPMatrix] = glGetUniformLocation(m_uProgram, kCCUniformMVPMatrix_s); m_uUniforms[kCCUniformTime] = glGetUniformLocation(m_uProgram, kCCUniformTime_s); m_uUniforms[kCCUniformSinTime] = glGetUniformLocation(m_uProgram, kCCUniformSinTime_s); m_uUniforms[kCCUniformCosTime] = glGetUniformLocation(m_uProgram, kCCUniformCosTime_s); m_bUsesTime = ( m_uUniforms[kCCUniformTime] != -1 || m_uUniforms[kCCUniformSinTime] != -1 || m_uUniforms[kCCUniformCosTime] != -1 ); m_uUniforms[kCCUniformRandom01] = glGetUniformLocation(m_uProgram, kCCUniformRandom01_s); m_uUniforms[kCCUniformSampler] = glGetUniformLocation(m_uProgram, kCCUniformSampler_s); this->use(); // Since sample most probably won't change, set it to 0 now. this->setUniformLocationWith1i(m_uUniforms[kCCUniformSampler], 0); } void CCGLProgram::setUniformLocationWith1i(GLint location, GLint i1) { 。。。。。 glUniform1i( (GLint)location, i1); 。。。。。 }
其中,kCCUniformSampler_s这个宏的定义为
#define kCCUniformSampler_s "CC_Texture0"
再翻下shader的代码:
ccShader_PositionTextureColor_frag.h " \n\ #ifdef GL_ES \n\ precision lowp float; \n\ #endif \n\ \n\ varying vec4 v_fragmentColor; \n\ varying vec2 v_texCoord; \n\ uniform sampler2D CC_Texture0; \n\ \n\ void main() \n\ { \n\ gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord); \n\ } \n\ ";
到了这里就很清楚了,在把shader读入到缓存的过程中,CC_Texture0这个uniform 最终被绑定到了‘0’这个位置上。
这里在分析一个draw中用到的一个函数:
//==>>如果调用了ccGLBindTexture2D,那么就直接将图像纹理textureId绑定到位置0上 void ccGLBindTexture2D(GLuint textureId) { ccGLBindTexture2DN(0, textureId); } //==>>将纹理textureId绑定到位置textureUnit上 void ccGLBindTexture2DN(GLuint textureUnit, GLuint textureId) { #if CC_ENABLE_GL_STATE_CACHE CCAssert(textureUnit < kCCMaxActiveTexture, "textureUnit is too big"); if (s_uCurrentBoundTexture[textureUnit] != textureId) { s_uCurrentBoundTexture[textureUnit] = textureId; //==>>glActiveTexture 函数设定当前的贴图单元,以至于后面的函数glBindTexture 绑定贴图到当前的单元 glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_2D, textureId);//==>>将纹理textureId绑定到已经激活的位置上 } #else glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_2D, textureId); #endif }
然后来看下draw方法,就比较简单了。
void CCSprite::draw(void) { CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); CCAssert(!m_pobBatchNode, "If CCSprite is being rendered by CCSpriteBatchNode, CCSprite#draw SHOULD NOT be called"); CC_NODE_DRAW_SETUP(); //==>>设置混合模式 ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); //==>>将纹理绑定到opengl上 ccGLBindTexture2D( m_pobTexture->getName() ); //==>>允许顶点,纹理位置,颜色等坐标输入 ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); #define kQuadSize sizeof(m_sQuad.bl) #ifdef EMSCRIPTEN long offset = 0; setGLBufferData(&m_sQuad, 4 * kQuadSize, 0); #else long offset = (long)&m_sQuad; #endif // EMSCRIPTEN //==>>我们知道了ccV3F_C4B_T2F这个结构体的类型和指针,那么就可以通过offset方式来获取到里面指定成员变量的位置,然后就可以 //==>>通过(void*) (offset + diff)获取指定成员变量的位置。 // vertex int diff = offsetof( ccV3F_C4B_T2F, vertices); glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); // texCoods diff = offsetof( ccV3F_C4B_T2F, texCoords); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); // color diff = offsetof( ccV3F_C4B_T2F, colors); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); //==>>画图 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 。。。。。 。。。。。 }
发表评论