Cocos2dx源码记录(3) CCVertexIndexData

CCVertexIndexData 主要用于保存实际持有vbo的VertexBuffer 类和 VertexStreanAtrribute 结构体的文件。 #1 VertexData 实际使用的对象

class CC_DLL VertexData : public Ref
{
public:
    /**
    Create function, used to create a instance of VertexData.
    */
    static VertexData* create();
    
    /**
    Get the number of streams in the VertexData.
    */
    size_t getVertexStreamCount() const;
    /**
    Set a stream to VertexData,given that stream is identified by semantic, so if the semantic is not
    specified before, it will add a stream, or it will override the old one.
    @param buffer The binding buffer of the stream.
    @param stream The binding vertex attribute, its member semantic will be used as the identifier.
    */
    bool setStream(VertexBuffer* buffer, const VertexStreamAttribute& stream);
    /**
    Remove the given streams.
    @param semantic The semantic of the stream.
    */
    void removeStream(int semantic);
    /**
    Get the attribute of stream, const version.
    @param semantic The semantic of the stream.
    */
    const VertexStreamAttribute* getStreamAttribute(int semantic) const;
    /**
    Get the attribute of stream.
    @param semantic The semantic of the stream.
    */
    VertexStreamAttribute* getStreamAttribute(int semantic);
    /**
    Get the binded buffer of the stream.
    @param semantic The semantic of the stream.
    */
    VertexBuffer* getStreamBuffer(int semantic) const;
    
    /**
    Called for rendering, it will bind the state of vertex data to current rendering pipeline.
    */
    void use();
//.......
protected:
    /**
    Simple struct to bundle buffer and attribute.
    */
    struct BufferAttribute
    {
        VertexBuffer* _buffer;
        VertexStreamAttribute _stream;
    };
    
    /**
    Streams in the VertexData.
    */
    std::map<int, BufferAttribute> _vertexStreams;
};
复制代码

其中除了一系列设置属性获取属性的方法外最重要的就是 _vertexStreams 和 use()方法 _vertexStreams 保存了持有gl层使用 的顶点缓存对像即vbo的vertexBuffer 和用于glVertexAttributePointer*()方法的 VertexStreamAttribute 结构体, 实际的使用方法都在use方法内

void VertexData::use()
{
    uint32_t flags(0);
    for(auto& element : _vertexStreams)
    {
        flags = flags | (1 << element.second._stream._semantic);
    }
    
    GL::enableVertexAttribs(flags);

    int lastVBO = -1;
    for(auto& element : _vertexStreams)
    {
        //glEnableVertexAttribArray((GLint)element.second._stream._semantic);
        auto vertexStreamAttrib = element.second._stream;
        auto vertexBuffer = element.second._buffer;

        // don't call glBindBuffer() if not needed. Expensive operation.
        int vbo = vertexBuffer->getVBO();
        if (vbo != lastVBO) {
            glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->getVBO());
            lastVBO = vbo;
        }
        glVertexAttribPointer(GLint(vertexStreamAttrib._semantic),
                              vertexStreamAttrib._size,
                              vertexStreamAttrib._type,
                              vertexStreamAttrib._normalize,
                              vertexBuffer->getSizePerVertex(),
                              (GLvoid*)((long)vertexStreamAttrib._offset));
    }
}
复制代码

glVertexAttribPointer方法各参数的意义在之前的日记中有提到过这里就不说明了,会与 对应的vertexStreamAttribute各参数的一同说明

#VertexStreamAttribute 保存了顶点着色器的顶点属性的绑定参数

struct CC_DLL VertexStreamAttribute
{
    /**
     Constructor.
     */
    VertexStreamAttribute()
    : _normalize(false),_offset(0),_semantic(0),_type(0),_size(0)
    {
    }
    /**
     Constructor
     @param offset The offset of the attribute.
     @param semantic The semantic (Position, Texcoord, Color etc) of attribute.
     @param type The type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
     @param size Describe how many elements of type in the attribute.
     */
    VertexStreamAttribute(int offset, int semantic, int type, int size)
    : _normalize(false),_offset(offset),_semantic(semantic),_type(type),_size(size)
    {
    }
    /**
     Constructor
     @param offset The offset of the attribute.
     @param semantic The semantic (Position, Texcoord, Color etc) of attribute.
     @param type The type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
     @param size Describe how many elements of type in the attribute.
     @param normalize If true, the data will be normalized by dividing 255.
     */
    VertexStreamAttribute(int offset, int semantic, int type, int size, bool normalize)
    : _normalize(normalize),_offset(offset),_semantic(semantic),_type(type),_size(size)
    {
    }
    /**
     Whether the attribute should be normalized or not.
     */
    bool _normalize;
    /**
     The offset of the attribute in the buffer.
     */
    int _offset;
    /**
     Describe that the attribute usage, could be Position, Color etc.
      这里应该对应的是之前GLProgram里声明的顶点属性名称 枚举里的值
     */
    int _semantic;
    /**
     Describe the type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
     */
    int _type;
    /**
     Describe how many elements of type in the attribute.
     */
    int _size;
};
复制代码

感觉这个应该放在上面的VertexData的use方法上面说明,应该更合适些 这里估计一种顶点属性就会有一个对应的VertexStreamAttribute 所以如果你需要往顶点shader里传递Position TexCoord 等多个绑定顶点属性时就需要创建多个VertexStreamAttribute, 这些都是在引擎底层实现的使用者基本上不需要去管理

VertexBuffer

实际持有opengl 提供的vbo索引的cocos对象

lass CC_DLL VertexBuffer : public Ref
{
public:
    /**
    Create an instance of VertexBuffer.
    @param sizePerVertex Size in bytes of one vertex.
    @param vertexNumber The number of vertex.
    @param usage A hint to indicate whether the vertexBuffer are updated frequently or not to let GL optimise it.
    */
    static VertexBuffer* create(int sizePerVertex, int vertexNumber, GLenum usage = GL_STATIC_DRAW);
    /**Get the size in bytes of one vertex.*/
    int getSizePerVertex() const;
    /**Get the number of vertices.*/
    int getVertexNumber() const;
    /**
    Update all or part of vertices data, if the range specified exceeds the vertex buffer, it will be clipped.
    @param verts The pointer of the vertex data.
    @param count The number of vertices to update.
    @param begin The first vertex to update.
    */
    bool updateVertices(const void* verts, int count, int begin);

    /**
    Get the size of the vertex array in bytes, equals getSizePerVertex() * getVertexNumber().
    */
    int getSize() const;
    /**
    Get the internal openGL handle.
    */
    GLuint getVBO() const;
    
protected:
    /**
    Constructor.
    */
    VertexBuffer();
    /**
    Destructor.
    */
    virtual ~VertexBuffer();
    /**
    Init the storage of vertex buffer.
    @param sizePerVertex Size in bytes of one vertex.
    @param vertexNumber The number of vertex.
    @param usage A hint to indicate whether the vertexBuffer are updated frequently or not to let GL optimise it.
    */
    bool init(int sizePerVertex, int vertexNumber, GLenum usage = GL_STATIC_DRAW);
protected:
    /**
    Event handler for foreground.
    */
    void recreateVBO() const;
    /**
    Event listener for foreground.
    */
    EventListenerCustom* _recreateVBOEventListener;
protected:
    /**
    Internal handle for openGL.
    */
    mutable GLuint _vbo;
    /**
    Size in bytes for one vertex.
    */
    int _sizePerVertex;
    /**
    Number of vertices.
    */
    int _vertexNumber;
    /**
    Buffer used for shadow copy.
    */
    std::vector<unsigned char> _shadowCopy;
    /**
    Hint for optimisation in GL.
    */
    GLenum _usage;
protected:
    /**
    Static member to indicate that use _shadowCopy or not. 
    */
    static bool _enableShadowCopy;
public:
    /**
    Static getter for shadowCopy.
    */
    static bool isShadowCopyEnabled() { return _enableShadowCopy; }
    /**
     Static setter for shadowCopy.
     */
    static void enableShadowCopy(bool enabled) { _enableShadowCopy = enabled; }
};
复制代码

如果有opengl基础的同学估计看到这些方法的时候就知道这个类是干什么的了

bool VertexBuffer::init(int sizePerVertex, int vertexNumber, GLenum usage/* = GL_STATIC_DRAW*/)
{
    if(0 == sizePerVertex || 0 == vertexNumber)
        return false;
    _sizePerVertex = sizePerVertex;
    _vertexNumber = vertexNumber;
    _usage = usage;
    
    if(isShadowCopyEnabled())
    {
        _shadowCopy.resize(sizePerVertex * _vertexNumber);
    }
    
    glGenBuffers(1, &_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, getSize(), nullptr, _usage);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    return true;
}
复制代码

看到上面init函数的实现后是不是一下子就看懂了,这就是个用来管理对应VBO的管理对象(Cocos中使用了大量这种对象, 基本上使用到的opengl里的handler都有对应的管理对象,就像CCGLProgram)

bool VertexBuffer::updateVertices(const void* verts, int count, int begin)
{
    if(count <= 0 || nullptr == verts) return false;
    
    if(begin < 0)
    {
        CCLOGERROR("Update vertices with begin = %d, will set begin to 0", begin);
        begin = 0;
    }
    
    if(count + begin > _vertexNumber)
    {
        CCLOGERROR("updated vertices exceed the max size of vertex buffer, will set count to _vertexNumber-begin");
        count = _vertexNumber - begin;
    }
    
    if(isShadowCopyEnabled())
    {
        memcpy(&_shadowCopy[begin * _sizePerVertex], verts, count * _sizePerVertex);
    }
    
    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferSubData(GL_ARRAY_BUFFER, begin * _sizePerVertex, count * _sizePerVertex, verts); 
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    return true;
}
复制代码

上面是VertexBuffer的刷新方法, 绑定对应VBO 使用glsubData类型方法修改VBO缓存中对应区域的数据

#IndexBuffer IndexBuffer 和VertexBuffer实际上功能差不多,但是是用于保存顶点索引缓存的主要用于Mesh等有指定渲染顺序的功能的,它绑定的VBO单独用于保存顶点索引 GL_ELEMENT_ARRAY_BUFFER (并没有在CCVertexIndexData文件中发现IndexData这个类, 可能跟它并不需要使用VertexStreamAttribute类似的结构体的关系吧,虽然这个索引的正确性决定了你最终的渲染结果,可能跟数据量和复杂度有关)

转载于:https://juejin.im/post/5a30dd42f265da431b6d3262

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值