Search code examples
c++opengl-3vao

Using VAO with glDrawElements


I'm trying (for the first time) to use OpenGL 3.2 to draw some sprites to the screen. I'm trying to set up a VAO, but it's not working. I'm getting an EXC_BAD_ACCESS on the call to glDrawElements.

VAO setup:

// setting up VAO

glGenVertexArrays(1, &vao_);

glBindVertexArray(vao_);

glGenBuffers(1, &indices_id_);

glGenBuffers(1, &attributes_id_);

glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);

constexpr GLfloat* ptr = 0;

::glVertexAttribPointer(attribute_position_, 2, GL_FLOAT, false, STRIDE, ptr);
::glVertexAttribPointer(attribute_region_, 2, GL_FLOAT, false, STRIDE, ptr + 2);
::glVertexAttribPointer(attribute_color_, 4, GL_FLOAT, false, STRIDE, ptr + 4);

::glEnableVertexAttribArray(attribute_position_);
::glEnableVertexAttribArray(attribute_region_);
::glEnableVertexAttribArray(attribute_color_);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);

{
    auto data = std::make_unique<short[]>(BATCH_SIZE * 6);

    short j = 0;

    for (std::size_t i = 0; i < BATCH_SIZE * 6; i += 6, j += 4)
    {
        data[i] = j;
        data[i + 1] = (short)(j + 1);
        data[i + 2] = (short)(j + 2);
        data[i + 3] = (short)(j + 2);
        data[i + 4] = (short)(j + 3);
        data[i + 5] = j;
    }

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>(BATCH_SIZE * 6 * sizeof(short)), data.get(), GL_STATIC_DRAW);
}

glBindVertexArray(0);

Then elsewhere in the drawing loop:

// drawing

glBindVertexArray(vao_);

glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(float) * buffer_index_), attributes_.data(), GL_DYNAMIC_DRAW);

glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(6 * number_of_sprites_), GL_UNSIGNED_SHORT, 0);

glBindVertexArray(0);

Can anyone see what I'm doing wrong?

UPDATE

I've added the suggested changes (very grateful for those). However, I'm now finding that I need to add a call to glBindBuffer(GL_ARRAY_BUFFER, attributes_id_);before glBindVertexArray(vao_); when drawing to get rid of the EXC_BAD_ACCESS error.


Solution

  • OpenGL 4.6 API Core Profile Specification; 10.3. VERTEX ARRAYS; page 347

    A vertex array object is created by binding a name returned by GenVertexArrays with the command

    void BindVertexArray( uint array );
    

    array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.4- 23.7.

    Table 23.4 contains ELEMENT_ARRAY_BUFFER_BINDING


    This means, that the state of the bound ELEMENT_ARRAY_BUFFER is stored in the Vertex Array Object.

    In your case indices_id_ is stored in the state vector of vao_, because of

    glBindVertexArray(vao_);
    
    .....
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
    

    When you call

    glBindVertexArray(0);
    

    then indices_id_ is not longer in the current state vector.

    You have to change the order of the instructions:

    glBindVertexArray(vao_);
    
    .....
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_id_);
    {
        .....
        glBufferData(indices_id_, static_cast<GLsizeiptr>(BATCH_SIZE * 6), data.get(), GL_STATIC_DRAW);
    }
    glBindVertexArray(0);