Search code examples
c++openglglutvbo

Using OpenGL VBOs with custom classes/datatructures


I am trying to optimize the drawing of my quads (currently using glBegin and glEnd), and I read that a VBO is a better way to do this. My issue is that I don't have a basic array of GLuint with an index array, but rather custom classes to hold the values:

Location.hpp: Holds x, y, and z info

class Location {
public:
    Location(int x_, int y_, int z_);
    ~Location();

    int x;
    int y;
    int z;
}; 

Face.hpp: Holds 4 Location*s that mark the corners

class Face {
public:
    Face(Location* bl_, Location* br_, Location* tr_, Location* tl_); // Using point
    Face(int bl_[3], int br_[3], int tr_[3], int tl_[3]); // Using {x, y, z} int array
    ~Face();
    Location* bl = NULL; // Bottom Left
    Location* br = NULL; // Bottom Right
    Location* tr = NULL; // Top Right
    Location* tl = NULL; // Top Left
};

My question, is that I have a vector of faces (std::vector<Face*> facesToRender;) that I would like to display on the screen.

Right now I have a loop to do this:

Info:

The Chunk class creates a facesToRender and I believe this is where I can put a vboId)

chunks is an array of Chunk*s

glPushMatrix();
    for (int i = 0; i < chunks.size(); i++) {
        Chunk* chunk = chunks[i];
        for (int j = 0; j < chunk->facesToRender.size(); j++) {
            Face* f = chunk->facesToRender[j];
            srand(i); // Create a color per chunk
            glColor3ub(rand()%255, rand()%255, rand()%255);
            glBegin(GL_QUADS);
            glVertex3i(f->bl->x, f->bl->y, f->bl->z);
            glVertex3i(f->br->x, f->br->y, f->br->z);
            glVertex3i(f->tr->x, f->tr->y, f->tr->z);
            glVertex3i(f->tl->x, f->tl->y, f->tl->z);
            glEnd();
        }
    }
glPopMatrix();

My question is how to process this facesToRender vector into a VBO to have it display. I am a beginner at OpenGL and C++ (although I know other languages, so sorry if I made some big mistake with the classes).

If any additional info is needed please comment!


Solution

  • First of all you have to ensure that the vertex coordinates are in a contiguous and contiguous area in memory and are not fragmented into a lot of little pieces. Use Location bl, br, tr, tl instead of Location *bl ... and std::vector<Face> instead of std::vector<Face*>. Then you have a consecutive list of vertex coordinates which can be bound to a vertex buffer object:

    class Face {
    public:
        Location bl;
        Location br;
        Location tr;
        Location tl;
    };
    
    std::vector<Location> faces;
    

    Create the vetrtex array object and bind the data

    GLuint vbo;
    glGenBuffers( 1, &vbo );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, faces.size()*sizeof(*faces.data()), faces.data(), GL_STATIC_DRAW );
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    

    Draw the mesh:

    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glVertexPointer( 3, GL_INT, sizeof(Location), nullptr );
    glEnableClientState( GL_VERTEX_ARRAY );    
    
    glPushMatrix();
    for (int i = 0; i < chunks.size(); i++) {
        Chunk* chunk = chunks[i];
        for (int j = 0; j < chunk->facesToRender.size(); j++) {
            Face* f = chunk->facesToRender[j];
            srand(i); // Create a color per chunk
    
            glColor3ub(rand()%255, rand()%255, rand()%255);            
            glDrawArrays(GL_QUADS, j*4, 4);
        }
    }
    glPopMatrix();
    
    glDisableClientState( GL_VERTEX_ARRAY );
    



    As an alternative you can create a list of vertex coordinates and a list of faces which each contains the 4 indices of the corner coordinates.

    std::vector<Location> vertices;
    
    struct Face
    {
        int bl;
        int br;
        int tr;
        int tl;
    };
    
    std::vector<Face> faces;
    

    Indexed vertex cordiaten can be drawn by glDrawElements.