Reputation: 513
I'm attempting to copy two vertex buffer objects from one Mesh
object to another, through the copy assignment operator. Initially, my Vertex Array Object and the Buffers are initialized as follows:
void Mesh::construct(Vertex* vertices, unsigned int nVerts) {
vertexCount = nVerts;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
positions.reserve(nVerts);
texCoords.reserve(nVerts);
for (unsigned int i = 0; i < nVerts; i++) {
positions.push_back(vertices[i].getPosition());
texCoords.push_back(vertices[i].getTexCoord());
}
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
This works fine when instantiating a Mesh
object, and calling:
void Mesh::render() {
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
glBindVertexArray(0);
}
However, when I try to copy the mesh into another, and render it, I get a segmentation fault on the glDrawArrays(GL_TRIANGLES, 0, vertexCount);
line.. This is my copy assignment operator:
Mesh& Mesh::operator=(const Mesh& param) {
if (this == ¶m) {
return *this;
} else {
GLint size = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
// Vertices
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[POSITION_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[POSITION_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Texture Coords
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[TEXCOORD_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Unbind buffers
glBindVertexArray(0);
this->vertexCount = param.vertexCount;
return *this;
}
}
Can anyone see any problems with this? I've checked that the size being returned from glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
is correct in both cases (for both position and texture coordinate buffer). I've also checked glGetError()
after both calls to glCopyBufferSubData
, which both return 0. Not sure what to try next? My error may be elsewhere, but this is the first time I have tried copying buffers, so want to check that I'm doing that part right. If it helps, my Mesh
destructor is:
Mesh::~Mesh() {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(NUM_BUFFERS, vab);
}
Through a debugger I can see that this is, of course, being called once, after the line:
this->mesh = Mesh(*texture);
Which is simply constructing a mesh, then assigning it (the texture just sizes the quad to the size of the texture, and calls the constructor shown at the start with the correct vertex positions).
Upvotes: 1
Views: 3343
Reputation: 29240
You copy the arrays, but you never bind the copied versions to GL_ARRAY_BUFFER
, meaning your glVertexAttribPointer
calls are pointing to nothing.
I'm also a little wary of this code:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
It seems like the position vertex pointer will be referring to the texture data, because that's the currently bound vertex buffer when you call glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
I'd think you'd want the order to be like so:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I'm not certain. I usually interleave all my vertex attributes into a single vertex buffer.
Upvotes: 4