FinalFanatic
FinalFanatic

Reputation: 513

OpenGL Copy Vertex Buffer Object

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 == &param) {
        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

Answers (1)

Jherico
Jherico

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

Related Questions