Search code examples
carraysopenglvbovao

Generating Vertex Arrays for OpenGL


I want to use some convenience methods to generate vertex and colour arrays for use in objects. From what i've seen on generating arrays, this is an example of what I currently use:

GLfloat * CDMeshVertexesCreateRectangle(CGFloat height, CGFloat width) {

// Requires the rendering method GL_TRIANGLE_FAN
GLfloat *squareVertexes = (GLfloat *) malloc(8 * sizeof(GLfloat));
squareVertexes[0] = -(width / 2);
squareVertexes[1] = -(height / 2);
squareVertexes[2] = -(width / 2);
squareVertexes[3] = (height / 2);
squareVertexes[4] = (width / 2);
squareVertexes[5] = (height / 2);
squareVertexes[6] = (width / 2);
squareVertexes[7] = -(height / 2);

return squareVertexes;

}

But when i use it on something such as this:

GLuint memoryPointer = 0;
    GLuint colourMemoryPointer = 0;

    GLfloat *vertexes = CDMeshVertexesCreateRectangle(200, 200);
    GLfloat *colors = CDMeshColorsCreateGrey(1.0, 4);

    // Allocate the buffer
    glGenBuffers(1, &memoryPointer);
    // Bind the buffer object (tell OpenGL what to use)
    glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);

    // Allocate space for the VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);


    // Allocate the buffer
    glGenBuffers(1, &colourMemoryPointer);
    // Bind the buffer object (tell OpenGL what to use)
    glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);

    // Allocate space for the VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

    glEnableClientState(GL_VERTEX_ARRAY); // Activate vertex coordinates array
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
    glVertexPointer(2, GL_FLOAT, 0, 0);   

    glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
    glColorPointer(4, GL_FLOAT, 0, 0);

    //render
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY); // Deactivate vertex coordinates array
    glDisableClientState(GL_COLOR_ARRAY);

    free(vertexes);
    free(colors);

The rendering doesn't hold up, and random problems occur during rendering such as flickering, color distortion and more. When using the same code for initialisation and rendering when using a normally defined array (removing the generated vertexes and its related code), no problems occur.

GLfloat Square[8] = {
-100, -100,
-100, 100,
100, 100,
100, -100
};

Does anyone know where i'm going wrong?


Solution

  • You have two problems in your code. First this pattern:

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
    

    sizeof(vertexes) evaluates to the size of the pointer variable, not the size of the buffer. C/C++ newbie mistake, we all did it. You need to keep track of the size yourself. So do it like this:

    int allocate_a_buffer(CGFloat height, CGFloat width, GLfloat **buffer, size_t *buffer_size) 
    {
    // Requires the rendering method GL_TRIANGLE_FAN
        return  ( *buffer = (GLfloat *) malloc( *buffer_size = ( <xxx> * sizeof(GLfloat)) ) ) != 0;
    }
    

    and

    GLfloat *vertices;
    size_t vertices_size;
    
    if( !allocate_a_buffer(..., &vertices, &vertices_size) ) {
        error();
        return;
    }
    glBufferData(GL_ARRAY_BUFFER, vertices_size, vertices, GL_STATIC_DRAW);
    

    If you're using C++ just use a std::vector passed by reference:

    void initialize_buffer(..., std::vector<GLfloat> &buffer)
    {
        buffer.resize(...);
        for(int n = ...; ...; ...) {
             buffer[n] = ...;
        }
    }
    

    and

    std::vector<GLfloat> vertices;
    initialize_buffer(..., vertices);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);
    

    much less fuzz.


    The other problem is, that this code seems to be called by the drawing function. The whole point of buffer objects is, that you initialize them only one time and then only bind and draw from them in the display routine. So glDrawArrays belongs into another function than the rest of this code, namely the display routine, while the rest belongs into the data loading and scene data management code.