Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

glDrawElements crash (OpenGL 3.2 / Windows 7)

I'm trying to draw a simple quad in OpenGL 3.2 however the application crashes with "Access violation reading location 0x00000000" when I call "glDrawElements".

I assume the issue is that the Vertex Buffer data is wrong, but I am unsure how to fix the issue / debug it (an OpenGL trace would be fantastic but I do not know how to enable this either...)

Initialization code:

std::vector<CUShort> Indices;
const CUShort IndicesArray[] = { 0, 1, 2, 2, 0, 3 };

for(size_t j = 0; j < 1; j++) {
    for(size_t i = 0; i < sizeof(IndicesArray) / sizeof(*IndicesArray); i++) {
        Indices.push_back(4 * j + IndicesArray[i]);
    }
}

glGenBuffers(1, &m_Elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

glGenVertexArrays(1, &m_Array);
glBindVertexArray(m_Array);

glGenBuffers(1, &m_Buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_TRUE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Color));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Position));

glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Texcoord));

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

Drawing code:

glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);

TexColorVertex Vertices[4];

glm::vec4 SpritePos = glm::vec4(0, 0, 1024.0f, 384.0f);
Vertices[0].Position = glm::vec2(SpritePos.x, SpritePos.y);
Vertices[1].Position = glm::vec2(SpritePos.x, SpritePos.w);
Vertices[2].Position = glm::vec2(SpritePos.z, SpritePos.w);
Vertices[3].Position = glm::vec2(SpritePos.z, SpritePos.y);

Color Kittens = Color::HotPink();
Vertices[0].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[1].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[2].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[3].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);

Vertices[0].Texcoord = glm::vec2(0.0f, 0.0f);
Vertices[1].Texcoord = glm::vec2(0.0f, 1.0f);
Vertices[2].Texcoord = glm::vec2(1.0f, 1.0f);
Vertices[3].Texcoord = glm::vec2(1.0f, 0.0f);

glBufferSubData(GL_ARRAY_BUFFER, sizeof(Vertices), sizeof(Vertices), Vertices);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray(m_Array);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const GLvoid*)0);

The vertex struct is declared as such:

struct TexColorVertex
{
    TexColorVertex(void) { }
    TexColorVertex(glm::vec2 const& Position, glm::vec2 const& Texcoord) :
        Position(Position), Texcoord(Texcoord)
    { }
    glm::vec2 Position;
    glm::vec2 Texcoord;
    glm::vec4 Color;
};

Does anyone have any suggestions on how to fix this and draw a simple quad that takes up half the screen?

like image 468
Nate Strandberg Avatar asked Dec 02 '22 16:12

Nate Strandberg


1 Answers

While user3256930 does bring up a valid point about the allocated size of your buffer, that is actually not the cause of your crash.

The problem is not with glBufferSubData (...), but rather with the call to glDrawElements (...). This call is attempting to dereference a NULL pointer, which is a red flag that nothing is bound to GL_ELEMENT_ARRAY_BUFFER.

When nothing is bound to GL_ELEMENT_ARRAY_BUFFER, then the pointer you pass to glDrawElements (...) is an actual pointer to client memory rather than an offset into Buffer Object (server) memory.


To understand why this occurs, recall what Vertex Array Objects store:

  1. Vertex Attribute State [Pointers, Enable/Disable]
  2. Element Array Buffer Binding (GL_ELEMENT_ARRAY_BUFFER)

Now, consider the order of these two calls:

glBindBuffer      (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray (m_Array);

First you bind something to GL_ELEMENT_ARRAY_BUFFER (m_Elements) and immediately afterwards you bind a Vertex Array Object (m_Array), which replaces the element array buffer you just bound with the binding it keeps track of internally.

You should consider either (1) using your VAO to persistently reference a single element array buffer or (2) reversing the order of these two calls.


If your Vertex Array Object (m_Array) will always be used with the same element array buffer, then I would suggest you use the first approach. This can be implemented simply by moving the following code in your initialization:

glGenVertexArrays (1, &m_Array);
glBindVertexArray (m_Array);

To come before:

glGenBuffers (1, &m_Elements);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

With this approach, nothing needs to be explicitly bound to GL_ELEMENT_ARRAY_BUFFER in your drawing code.

like image 111
Andon M. Coleman Avatar answered Dec 10 '22 03:12

Andon M. Coleman