2

I am trying to draw part of my tile image but I am getting GL_INVALID_VALUE error when I call glDrawElements function. There is no problem when I change this function with glDrawArrays. The problem is that the indices count parameter is not negative number.

There is a code:

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
 #define VERTEX_ATTR_PTR(loc, count, member, type) \
    glEnableVertexAttribArray(loc); \
    glVertexAttribPointer(loc, count, GL_FLOAT, GL_FALSE, sizeof(type),  BUFFER_OFFSET(offsetof(struct type, member)))
// ---------- TextRenderer
void TextRenderer::setText(const string& text) {
    vector<Vertex2f> vertex_buffer;
    vector<GLuint> index_buffer;

    GLfloat cursor = 0.f;
    FPoint2D cell_size = font->getCellSize();

    for (char c : text) {
        TILE_ITER iter = font->getCharacter(c);
        {
            // UV
            for (GLuint i = 0; i < 4; ++i) {
                TILE_ITER _v = iter + i;
                vertex_buffer.push_back( {
                        {
                                _v->pos[0]  + cursor,
                                _v->pos[1],
                                _v->pos[2]
                        },
                        { _v->uv[0], _v->uv[1] }
                });
            }
            // Index
            for (GLuint i = 0; i < 6; ++i)
                index_buffer.push_back(
                        Tile::indices[i] + vertex_buffer.size() - 4);
        }
        cursor += cell_size.X;
    }

    vertices_count = vertex_buffer.size();
    indices_count = index_buffer.size();

    glBindVertexArray(vao);
    {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,
                0,
                indices_count * sizeof(GLuint),
                &index_buffer[0]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferSubData(GL_ARRAY_BUFFER,
                0,
                vertices_count * sizeof(Vertex2f),
                &vertex_buffer[0]);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    glBindVertexArray(0);
}
void TextRenderer::create() {
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    {
        indices = genGLBuffer( {
                nullptr,
                BUFFER_SIZE / 2 * sizeof(GLuint),
                GL_ELEMENT_ARRAY_BUFFER
        }, true, GL_DYNAMIC_DRAW);

        vbo = genGLBuffer( {
                nullptr,
                BUFFER_SIZE * sizeof(Vertex2f),
                GL_ARRAY_BUFFER
        }, true, GL_DYNAMIC_DRAW);

        VERTEX_ATTR_PTR(0, 3, pos, Vertex2f); // Vertex
        VERTEX_ATTR_PTR(1, 2, uv, Vertex2f); // UV
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    setText("DUPA");
}
void TextRenderer::draw(MatrixStack& matrix, GLint) {
    static Shader shader(
            getFileContents("shaders/text_frag.glsl"),
            getFileContents("shaders/text_vert.glsl"),
            "");

    shader.begin();
    shader.setUniform(GL_TEXTURE_2D, "texture", 0,
            font->getHandle());
    shader.setUniform("matrix.mvp", matrix.vp_matrix * matrix.model);
    shader.setUniform("col", col);
    {
        glBindVertexArray(vao);
        //glDrawArrays(GL_LINE_STRIP, 0, vertices_count);
        glDrawElements(GL_LINES, indices_count, GL_UNSIGNED_INT,
                nullptr);
        glBindVertexArray(0);
        showGLErrors();
    }
    shader.end();
}
Cœur
  • 32,421
  • 21
  • 173
  • 232

2 Answers2

4

The problem is with the following (shortened) call sequence in your setText() method:

glBindVertexArray(vao);
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    ...
}
glBindVertexArray(0);

The binding of the GL_ELEMENT_ARRAY_BUFFER is part of the VAO state. So by making this call while the VAO is bound:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

you're setting the VAO state to have an element array buffer binding of 0. So when you later bind the VAO in your draw() method, you won't have a binding for GL_ELEMENT_ARRAY_BUFFER.

To avoid this, the simplest solution is to just remove that call. If you want to explicitly unbind it because you're worried that having it bound might have undesired side effects on other code, you need to move it after unbinding the VAO:

glBindVertexArray(vao);
{
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ...);

    ...
}
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Reto Koradi
  • 49,246
  • 7
  • 76
  • 116
1

Without seeing the whole code and knowing exact GL version, I will attempt to give you a correct answer.

First, if you're using ES2 then using index type as GL_UNSIGNED_INT is not supported by default, however I don't think that's your problem.

Your actual issue is that element arrays are actually not stored in your VAO object, only vertex data configuration. Therefore glDrawElements will give you this error as it will think no element array is bound and you passed NULL as indices argument to the function.

To solve this, bind the appropriate element array before you call glDrawElements

user3747345
  • 398
  • 1
  • 6
  • Thank you! I added glBindBuffer(GL_ELEMENT..) before glDrawElements and it's working! – Mati Bagiński Jul 12 '14 at 09:29
  • The binding of the `GL_ELEMENT_ARRAY_BUFFER` is in fact part of the VAO state. The problem here was that the code explicitly unbinds it with `glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)` while the VAO is bound. If you remove that call, it will work just fine without having to explicitly bind the element buffer again before drawing. That's the whole idea of using VAO, you can set the entire state by just binding the VAO. – Reto Koradi Jul 12 '14 at 16:08