cocos2d理解--SpriteBatchNode和TextureAtlas

cocos2d理解--SpriteBatchNode和TextureAtlas,第1张

概述1:TextureAtlas 头文件: GLushort* _indices; //顶点index GLuint _VAOname; GLuint _buffersVBO[2]; //0: vertex 1: indices bool _dirty; //indicate 1:TextureAtlas

头文件:

glushort*           _indices;  //顶点index    gluint              _VAOname;    gluint              _buffersVBO[2]; //0: vertex 1: indices    bool                _dirty; //indicates whether or not the array buffer of the VBO needs to be updated    /** quantity of quads that are going to be drawn */    ssize_t _totalQuads;  //所有的顶点数量    /** quantity of quads that can be stored with the current texture atlas size */    ssize_t _capacity;    /** Texture of the texture atlas */    Texture2D* _texture;    /** Quads that are going to be rendered */    V3F_C4B_T2F_Quad* _quads;  //顶点数据源文件代码分析:``bool TextureAtlas::initWithTexture(Texture2D *texture,ssize_t capacity){    CCASSERT(capacity>=0,"Capacity must be >= 0");// CCASSERT(texture != nullptr,"texture should not be null");    _capacity = capacity; //预留的顶点数量    _totalQuads = 0;     // retained in property    this->_texture = texture;    CC_SAFE_RETAIN(_texture);    // Re-initialization is not allowed    CCASSERT(_quads == nullptr && _indices == nullptr,"");//给预留的顶点数量分配内存。每个顶点数据包括(位置---V3F,颜色---C4B,uv值---T2F)    _quads = (V3F_C4B_T2F_Quad*)malloc( _capacity * sizeof(V3F_C4B_T2F_Quad) );//所有构成三角形的顶点index,4个顶点有6个index(两个三角形)    _indices = (glushort *)malloc( _capacity * 6 * sizeof(glushort) );    if( ! ( _quads && _indices) && _capacity > 0)     {        //cclOG("cocos2d: TextureAtlas: not enough memory");        CC_SAFE_FREE(_quads);        CC_SAFE_FREE(_indices);        // release texture,should set it to null,because the destruction will        // release it too. see cocos2d-x issue #484        CC_SAFE_RELEASE_NulL(_texture);        return false;    }    memset( _quads,0,_capacity * sizeof(V3F_C4B_T2F_Quad) );    memset( _indices,_capacity * 6 * sizeof(glushort) );//.. ...省略部分代码    return true;}

voID TextureAtlas::setupIndices()
{
if (_capacity == 0)
return;

for( int i=0; i < _capacity; i++){    _indices[i*6+0] = i*4+0;  //第i*4+0个顶点构成2*i个三角形的第一个顶点    _indices[i*6+1] = i*4+1;  //第i*4+1个顶点构成2*i个三角形的第二个顶点    _indices[i*6+2] = i*4+2;  //第i*4+2个顶点构成2*i个三角形的第三个顶点    // inverted index. issue #179    _indices[i*6+3] = i*4+3;  //第i*4+3个顶点构成2*i+1个三角形的第一个顶点    _indices[i*6+4] = i*4+2;  //第i*4+2个顶点构成2*i+1个三角形的第二个顶点    _indices[i*6+5] = i*4+1;  //第i*4+1个顶点构成2*i+1个三角形的第三个顶点      }

}

``//将quad插入到所有数据的index位置中voID TextureAtlas::insertQuad(V3F_C4B_T2F_Quad *quad,ssize_t index){    CCASSERT( index>=0 && index<_capacity,"insertQuaDWithTexture: InvalID index");    _totalQuads++;  //顶点数量+1    CCASSERT( _totalQuads <= _capacity,"invalID totalQuads");    // issue #575. index can be > totalQuads    auto remaining = (_totalQuads-1) - index; //将index后面的remaining个顶点往后移。    // last object doesn't need to be moved    if( remaining > 0)     {        // texture coordinates        //移动remaining个数据往后移动。        memmove( &_quads[index+1],&_quads[index],sizeof(_quads[0]) * remaining );            }    _quads[index] = *quad;    _dirty = true;}
//将quads的amount个数据插入到所有数据的index位置上。voID TextureAtlas::insertQuads(V3F_C4B_T2F_Quad* quads,ssize_t index,ssize_t amount){    CCASSERT(index>=0 && amount>=0 && index+amount<=_capacity,"insertQuaDWithTexture: InvalID index + amount");    _totalQuads += amount;  //顶点数据+amount    CCASSERT( _totalQuads <= _capacity,"invalID totalQuads");    // issue #575. index can be > totalQuads    auto remaining = (_totalQuads-1) - index - amount;    // last object doesn't need to be moved    if( remaining > 0)    {        // tex coordinates        //将index后面的所有数据向后移动amount个位置        memmove( &_quads[index+amount],sizeof(_quads[0]) * remaining );    }    //设置index后面的数据    auto max = index + amount;    int j = 0;    for (ssize_t i = index; i < max ; i++)    {        _quads[index] = quads[j];        index++;        j++;    }    _dirty = true;}
//将oldindex位置的数据插入到newIndex的位置。并且中间的数据一并移动。//oldindex,A,A..,newIndex---->A,newIndex,oldindex。//newIndex,oldindex---->oldindex,A..。voID TextureAtlas::insertQuadFromIndex(ssize_t oldindex,ssize_t newIndex){    CCASSERT( newIndex >= 0 && newIndex < _totalQuads,"insertQuadFromIndex:atIndex: InvalID index");    CCASSERT( oldindex >= 0 && oldindex < _totalQuads,"insertQuadFromIndex:atIndex: InvalID index");    if( oldindex == newIndex )    {        return;    }    // because it is ambiguous in iphone,so we implement abs ourselves    // unsigned int howMany = abs( oldindex - newIndex); auto howMany = (oldindex - newIndex) > 0 ? (oldindex - newIndex) :  (newIndex - oldindex);    auto dst = oldindex;    auto src = oldindex + 1;    if( oldindex > newIndex)    {        dst = newIndex+1;        src = newIndex;    }    // texture coordinates    V3F_C4B_T2F_Quad quadsBackup = _quads[oldindex];    memmove( &_quads[dst],&_quads[src],sizeof(_quads[0]) * howMany );    _quads[newIndex] = quadsBackup;    _dirty = true;}
//删除index的数据,并且将index后面的 数据往前移动一个。voID TextureAtlas::removeQuadAtIndex(ssize_t index){    CCASSERT( index>=0 && index<_totalQuads,"removeQuadAtIndex: InvalID index");    auto remaining = (_totalQuads-1) - index;    // last object doesn't need to be moved    if( remaining )     {        // texture coordinates        memmove( &_quads[index],&_quads[index+1],sizeof(_quads[0]) * remaining );    }    _totalQuads--;    _dirty = true;}
//删除index开始的amount个数据,后面的数据往前移动voID TextureAtlas::removeQuadsAtIndex(ssize_t index,ssize_t amount){    CCASSERT(index>=0 && amount>=0 && index+amount<=_totalQuads,"removeQuadAtIndex: index + amount out of bounds");    auto remaining = (_totalQuads) - (index + amount);    _totalQuads -= amount;    if ( remaining )    {        memmove( &_quads[index],&_quads[index+amount],sizeof(_quads[0]) * remaining );    }    _dirty = true;}
//移动oldindex开始的amount到newIndex位置。voID TextureAtlas::moveQuadsFromIndex(ssize_t oldindex,ssize_t amount,ssize_t newIndex){    CCASSERT(oldindex>=0 && amount>=0 && newIndex>=0,"values must be >= 0");    CCASSERT(newIndex + amount <= _totalQuads,"insertQuadFromIndex:atIndex: InvalID index");    CCASSERT(oldindex < _totalQuads,"insertQuadFromIndex:atIndex: InvalID index");    if( oldindex == newIndex )    {        return;    }    //create buffer    size_t quadSize = sizeof(V3F_C4B_T2F_Quad);    V3F_C4B_T2F_Quad* tempQuads = (V3F_C4B_T2F_Quad*)malloc( quadSize * amount);    memcpy( tempQuads,&_quads[oldindex],quadSize * amount );    if (newIndex < oldindex)    {        // move quads from newIndex to newIndex + amount to make room for buffer        memmove( &_quads[newIndex],&_quads[newIndex+amount],(oldindex-newIndex)*quadSize);    }    else    {        // move quads above back        memmove( &_quads[oldindex],&_quads[oldindex+amount],(newIndex-oldindex)*quadSize);    }    memcpy( &_quads[newIndex],tempQuads,amount*quadSize);    free(tempQuads);    _dirty = true;}
//渲染start位置的numberOfQuads的数据voID TextureAtlas::drawNumberOfQuads(ssize_t numberOfQuads,ssize_t start){    CCASSERT(numberOfQuads>=0 && start>=0,"numberOfQuads and start must be >= 0");    if(!numberOfQuads)        return;    GL::bindTexture2D(_texture->getname());    if (Configuration::getInstance()->supportsShareableVAO()) { // // Using VBO and VAO // // FIXME:: update is done in draw... perhaps it should be done in a timer if (_dirty) { glBindBuffer(GL_ARRAY_BUFFER,_buffersVBO[0]); // option 1: subdata // glBufferSubData(GL_ARRAY_BUFFER,sizeof(_quads[0])*start,sizeof(_quads[0]) * n,&_quads[start] ); // option 2: data // glBufferData(GL_ARRAY_BUFFER,sizeof(quads_[0]) * (n-start),&quads_[start],GL_DYNAMIC_DRAW); // option 3: orphaning + glMapBuffer glBufferData(GL_ARRAY_BUFFER,sizeof(_quads[0]) * _capacity,nullptr,GL_DYNAMIC_DRAW); voID *buf = glMapBuffer(GL_ARRAY_BUFFER,GL_WRITE_ONLY); memcpy(buf,_quads,sizeof(_quads[0])* _totalQuads); glunmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER,0); _dirty = false; } GL::bindVAO(_VAOname); #if CC_REBIND_INDICES_BUFFER glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_buffersVBO[1]); #endif glDrawElements(GL_TRIANGLES,(GLsizei) numberOfQuads*6,GL_UNSIGNED_SHORT,(GLvoID*) (start*6*sizeof(_indices[0])) ); GL::bindVAO(0); #if CC_REBIND_INDICES_BUFFER glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); #endif // glBindVertexArray(0); } else { // // Using VBO without VAO // #define kQuadSize sizeof(_quads[0].bl) glBindBuffer(GL_ARRAY_BUFFER,_buffersVBO[0]); // FIXME:: update is done in draw... perhaps it should be done in a timer if (_dirty) { glBufferSubData(GL_ARRAY_BUFFER,sizeof(_quads[0]) * _totalQuads,&_quads[0] ); _dirty = false; } GL::enabLevertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_color_TEX); // vertices glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_position,3,GL_float,GL_FALSE,kQuadSize,(GLvoID*) offsetof(V3F_C4B_T2F,vertices)); // colors glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,4,GL_UNSIGNED_BYTE,GL_TRUE,colors)); // tex coords glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD,2,texCoords)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_buffersVBO[1]); glDrawElements(GL_TRIANGLES,(GLsizei)numberOfQuads*6,(GLvoID*) (start*6*sizeof(_indices[0]))); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); } CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,numberOfQuads*6); CHECK_GL_ERROR_DEBUG(); }
2:SpriteBatchNode
// addChild helper,faster than insertChildvoID SpriteBatchNode::appendChild(Sprite* sprite){    _reorderChildDirty=true;    sprite->setBatchNode(this);    sprite->setDirty(true);    if(_textureAtlas->getTotalQuads() == _textureAtlas->getCapacity()) {        increaseAtlasCapacity();    }    _descendants.push_back(sprite);//所有的子节点。    int index = static_cast<int>(_descendants.size()-1);    sprite->setAtlasIndex(index); 设置sprite的渲染节点为TextureAtlas的第index个数据    V3F_C4B_T2F_Quad quad = sprite->getQuad();      _textureAtlas->insertQuad(&quad,index);//将sprite的顶点数据传入到TextureAtlas的index位置。    // add children recursively    auto& children = sprite->getChildren();    for(const auto &child: children) {        appendChild(static_cast<Sprite*>(child)); //将sprite的所有数据加入到descendants。    }}
//将sprite的数据插入到TextureAtlas的index位置。但是现在还不append到spriteBatchNodevoID SpriteBatchNode::insertQuadFromSprite(Sprite *sprite,ssize_t index){    CCASSERT( sprite != nullptr,"Argument must be non-nullptr");    CCASSERT( dynamic_cast<Sprite*>(sprite),"CCSpriteBatchNode only supports Sprites as children");    // make needed room    while(index >= _textureAtlas->getCapacity() || _textureAtlas->getCapacity() == _textureAtlas->getTotalQuads())    {        this->increaseAtlasCapacity();    }    //    // update the quad directly. Don't add the sprite to the scene graph    //    sprite->setBatchNode(this);    sprite->setAtlasIndex(index);    V3F_C4B_T2F_Quad quad = sprite->getQuad();    _textureAtlas->insertQuad(&quad,index);    // FIXME:: updatetransform will update the textureAtlas too,using updateQuad.    // FIXME:: so,it should be AFTER the insertQuad    sprite->setDirty(true);    sprite->updatetransform();}
//获取sprite的第一个atlas 数据的indexssize_t SpriteBatchNode::atlasIndexForChild(Sprite *sprite,int nZ){    auto& siblings = sprite->getParent()->getChildren();    auto childindex = siblings.getIndex(sprite);    // ignore parent Z if parent is Spritesheet    bool ignoreParent = (SpriteBatchNode*)(sprite->getParent()) == this;    Sprite *prev = nullptr;    if (childindex > 0 && childindex != -1)    {        prev = static_cast<Sprite*>(siblings.at(childindex - 1));    }    // first child of the sprite sheet    if (ignoreParent)    {        if (childindex == 0)        {            return 0;        }        return highestAtlasIndexInChild(prev) + 1; //之前兄弟节点的最后一个子节点的index +1    }    // parent is a Sprite,so,it must be taken into account    // first child of an Sprite ?    if (childindex == 0)//第一个节点    {        Sprite *p = static_cast<Sprite*>(sprite->getParent());        // less than parent and brothers        if (nZ < 0)        {            return p->getAtlasIndex();//        }        else        {            return p->getAtlasIndex() + 1;//如果nz>=0,那么index是父节点的index +1。        }    }    else    {        // prevIoUs & sprite belong to the same branch        if ((prev->getLocalZOrder() < 0 && nZ < 0) || (prev->getLocalZOrder() >= 0 && nZ >= 0))        {            //prev和本 节点在同一批次,那么index是prev的最大index+1。            return highestAtlasIndexInChild(prev) + 1;          }        // else (prevIoUs < 0 and sprite >= 0 )        Sprite *p = static_cast<Sprite*>(sprite->getParent());//这种情况下,是父节点的index+1        return p->getAtlasIndex() + 1;    }    // Should not happen. Error calculating Z on Spritesheet    CCASSERT(0,"should not run here");    return 0;}
//sprite和sprite所有子节点的最大indexssize_t SpriteBatchNode::highestAtlasIndexInChild(Sprite *sprite){    auto& children = sprite->getChildren();    if (children.size() == 0)    {        return sprite->getAtlasIndex();    }    else    {        return highestAtlasIndexInChild( static_cast<Sprite*>(children.back()));    }}//sprite和sprite所有子节点的最小indexssize_t SpriteBatchNode::lowestAtlasIndexInChild(Sprite *sprite){    auto& children = sprite->getChildren();    if (children.size() == 0)    {        return sprite->getAtlasIndex();    }    else    {        return lowestAtlasIndexInChild(static_cast<Sprite*>(children.at(0)));    }}
//更新sprite和sprite子节点的atlas数据的index。voID SpriteBatchNode::updateAtlasIndex(Sprite* sprite,ssize_t* curIndex){    auto& array = sprite->getChildren();    auto count = array.size();    ssize_t oldindex = 0;    if( count == 0 )//如果没有子节点,那么sprite就是curIndex位置了    {        oldindex = sprite->getAtlasIndex();        sprite->setAtlasIndex(*curIndex);        sprite->setorderOfArrival(0);        if (oldindex != *curIndex){            swap(oldindex,*curIndex);        }        (*curIndex)++;    }    else    {        bool neednewIndex=true;        //先localZ<0的,然后sprite,最后localZ>0        //因为先对所有的子节点排序过。先localZ<0,然后localZ>0        if (array.at(0)->getLocalZOrder() >= 0)//如果第一个localZ>0那么先设置sprite的index        {            //all children are in front of the parent            oldindex = sprite->getAtlasIndex();            sprite->setAtlasIndex(*curIndex);            sprite->setorderOfArrival(0);            if (oldindex != *curIndex)            {                swap(oldindex,*curIndex);            }            (*curIndex)++;            neednewIndex = false;        }        for(const auto &child: array) {            Sprite* sp = static_cast<Sprite*>(child);            //找到了第一个localZorder>0的,设置sprite。            if (neednewIndex && sp->getLocalZOrder() >= 0)            {                oldindex = sprite->getAtlasIndex();                sprite->setAtlasIndex(*curIndex);                sprite->setorderOfArrival(0);                if (oldindex != *curIndex) {                    this->swap(oldindex,*curIndex);                }                (*curIndex)++;                neednewIndex = false;            }            updateAtlasIndex(sp,curIndex);        }        //这种情况是:所有的子节点都是localZ<0。        if (neednewIndex)        {//all children have a zOrder < 0)            oldindex = sprite->getAtlasIndex();            sprite->setAtlasIndex(*curIndex);            sprite->setorderOfArrival(0);            if (oldindex != *curIndex) {                swap(oldindex,*curIndex);            }            (*curIndex)++;        }    }}
总结

以上是内存溢出为你收集整理的cocos2d理解--SpriteBatchNode和TextureAtlas全部内容,希望文章能够帮你解决cocos2d理解--SpriteBatchNode和TextureAtlas所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/1080381.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-27
下一篇2022-05-27

发表评论

登录后才能评论

评论列表(0条)

    保存