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();
}
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
The problem is with the following (shortened) call sequence in your
setText()
method:The binding of the
GL_ELEMENT_ARRAY_BUFFER
is part of the VAO state. So by making this call while the VAO is bound:you're setting the VAO state to have an element array buffer binding of
0
. So when you later bind the VAO in yourdraw()
method, you won't have a binding forGL_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: