Cocos2dx源码记录(12) CCMeshCommand

465 阅读2分钟
class CC_DLL MeshCommand : public RenderCommand
{
public:

    MeshCommand();
    virtual ~MeshCommand();

    void init(float globalZOrder, Material* material, GLuint vertexBuffer, GLuint indexBuffer, GLenum primitive, GLenum indexFormat, ssize_t indexCount, const Mat4 &mv, uint32_t flags);

    void init(float globalZOrder, GLuint textureID, GLProgramState* glProgramState, RenderState::StateBlock* stateBlock, GLuint vertexBuffer, GLuint indexBuffer, GLenum primitive, GLenum indexFormat, ssize_t indexCount, const Mat4 &mv, uint32_t flags);

    void setDisplayColor(const Vec4& color);
    void setMatrixPalette(const Vec4* matrixPalette);
    void setMatrixPaletteSize(int size);
    void setLightMask(unsigned int lightmask);

    void execute();
    
    //used for batch
    void preBatchDraw();
    void batchDraw();
    void postBatchDraw();
    
    void genMaterialID(GLuint texID, void* glProgramState, GLuint vertexBuffer, GLuint indexBuffer, BlendFunc blend);
    
    uint32_t getMaterialID() const;
    
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    void listenRendererRecreated(EventCustom* event);
#endif

protected:
    //build & release vao
    void buildVAO();
    void releaseVAO();
    
    // apply renderstate, not used when using material
    void applyRenderState();


    Vec4 _displayColor; // in order to support tint and fade in fade out
    
    // used for skin
    const Vec4* _matrixPalette;
    int   _matrixPaletteSize;
    
    uint32_t _materialID; //material ID
    
    GLuint   _vao; //use vao if possible
    
    GLuint _vertexBuffer;
    GLuint _indexBuffer;
    GLenum _primitive;
    GLenum _indexFormat;
    ssize_t _indexCount;
    
    // States, default value all false


    // ModelView transform
    Mat4 _mv;

    // Mode A: Material
    // weak ref
    Material* _material;

    // Mode B: StateBlock
    // weak ref
    GLProgramState* _glProgramState;
    RenderState::StateBlock* _stateBlock;
    GLuint _textureID;


#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    EventListenerCustom* _rendererRecreatedListener;
#endif
};

##1.1 setDisplayColor 设置显示颜色

void MeshCommand::setDisplayColor(const Vec4& color)
{
    CCASSERT(!_material, "If using material, you should set the color as a uniform: use u_color");

    _displayColor = color;
}

##1.2 setMatrixPalette 设置调色板

void MeshCommand::setMatrixPalette(const Vec4* matrixPalette)
{
    CCASSERT(!_material, "If using material, you should set the color as a uniform: use u_matrixPalette");

    _matrixPalette = matrixPalette;
}

##1.3 setMatrixPaletteSize 设置调色板的数量

void MeshCommand::setMatrixPaletteSize(int size)
{
    CCASSERT(!_material, "If using material, you should set the color as a uniform: use u_matrixPalette with its size");

    _matrixPaletteSize = size;
}

##1.4 applyRenderState 提交渲染状态

void MeshCommand::applyRenderState()
{
    CCASSERT(!_material, "Must not be called when using materials");
    CCASSERT(_stateBlock, "StateBlock must be non null");

    // blend and texture
    GL::bindTexture2D(_textureID);
    //如果有_bits 枚举位 就根据_bits 重置state的值, 否则按defaultState重置
    _stateBlock->bind();
}

##1.5 batch 系列函数

//
void MeshCommand::preBatchDraw()
{
    // Do nothing if using material since each pass needs to bind its own VAO
    if (!_material)
    {
        if (Configuration::getInstance()->supportsShareableVAO() && _vao == 0)
            buildVAO();
        if (_vao)
        {
            GL::bindVAO(_vao);
        }
        else
        {
            glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);

            // FIXME: Assumes that all the passes in the Material share the same Vertex Attribs
            GLProgramState* programState = _material
                                            ? _material->_currentTechnique->_passes.at(0)->getGLProgramState()
                                            : _glProgramState;
            programState->applyAttributes();
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
        }
    }
}

void MeshCommand::batchDraw()
{
    if (_material)
    {
        for(const auto& pass: _material->_currentTechnique->_passes)
        {
            pass->bind(_mv);

            glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
            CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _indexCount);

            pass->unbind();
        }
    }
    else
    {
        _glProgramState->applyGLProgram(_mv);

        // set render state
        applyRenderState();

        // Draw
        glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
        CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _indexCount);
    }
}
void MeshCommand::postBatchDraw()
{
    // when using material, unbind is after draw
    if (!_material)
    {
        if (_vao)
        {
            GL::bindVAO(0);
        }
        else
        {
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
            glBindBuffer(GL_ARRAY_BUFFER, 0);
        }

        // restore the default state since we don't know
        // if the next command will need the default state or not
        RenderState::StateBlock::restore(0);
    }
}

##1.6 execute函数 在 isSkipBatching的情况下调用

void MeshCommand::execute()
{
    // Draw without VAO
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);

    if (_material)
    {
        for(const auto& pass: _material->_currentTechnique->_passes)
        {
            pass->bind(_mv, true);

            glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
            CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _indexCount);

            pass->unbind();
        }
    }
    else
    {
        // set render state
        _glProgramState->apply(_mv);

        applyRenderState();

        // Draw
        glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
        
        CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _indexCount);
    }

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

##1.7 这里用到的主要是Pass的 bind()函数

void Pass::bind(const Mat4& modelView, bool bindAttributes)
{

    // vertex attribs
    if (bindAttributes && _vertexAttribBinding)
        _vertexAttribBinding->bind();

    auto glprogramstate = _glProgramState ? _glProgramState : getTarget()->getGLProgramState();

    glprogramstate->applyGLProgram(modelView);
    glprogramstate->applyUniforms();

    //set render state
    RenderState::bind(this);

}

void VertexAttribBinding::bind()
{

    if (_handle)
    {
        // hardware
        GL::bindVAO(_handle);
    }
    else
    {
        // software
        //看来3d的还是牵连到很多其他类的感觉这个是第三方框架生成的
        auto meshVertexData = _meshIndexData->getMeshVertexData();
        glBindBuffer(GL_ARRAY_BUFFER, meshVertexData->getVertexBuffer()->getVBO());
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _meshIndexData->getIndexBuffer()->getVBO());

        // Software mode
        //根据位枚举的值设置 顶点属性的开关
        GL::enableVertexAttribs(_vertexAttribsFlags);
        // set attributes
        for(auto &attribute : _attributes)
        {
            //second实质上是一个vertexAttribValue
            attribute.second.apply();
        }
        
    }
}