0

What is the efficient way of using VertexBuffers? I'm drawing a simple cube (link to code). Ideally it should be such that I load the vertices onto the gpu once and then I don't have to copy them to the gpu everytime(which is what I'm doing inside renderScene, line 115). How do I do that? The code is provided here as well(It's derived from a tutorial):

//
// This code was created by Jeff Molofee '99 (ported to Linux/GLUT by Richard Campbell '99)
//
// If you've found this code useful, please let me know.
//
// Visit me at www.demonews.com/hosted/nehe 
// (email Richard Campbell at ulmont@bellsouth.net)
//
#include"stdafx.h"
//#include<glload\gl_3_1.h>
#include<Windows.h>
#include<GL/glew.h>
#include <GL/glut.h>    // Header File For The GLUT Library 
#include <GL/gl.h>  // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#include<GL/freeglut_ext.h>

//#include <unistd.h>     // Header File For sleeping.

/* ASCII code for the escape key. */
#include <stdlib.h>
#include <GL/glut.h>

// Location/Normals
#define X_POS 0
#define Y_POS 1
#define Z_POS 2

// Texture Coordinates
#define U_POS 0
#define V_POS 1

// Colours
#define R_POS 0
#define G_POS 1
#define B_POS 2
#define A_POS 3

// Vertex structure
typedef struct
{
    GLfloat location[3];
    GLfloat tex[2];
    GLfloat normal[3];
    GLfloat colour[4];
    GLubyte padding[16];
} Vertex;

// A helper macro to get a position
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#define INC_SCALE (1.00001)
// GLUT functions
void renderScene();
void changeSize(int w, int h);
void processNormalKeys(unsigned char key, int x, int y);

// VBO functions
void initVBO();

// Other functions
void buildCube();

// Globals - typically these would be in classes, 
// but in this simple example, I'm using globals
Vertex verts[24]; // We're making a cube, 6 faces * 4 verticies per face
GLubyte index[36]; // 2 Triangles per face (possible to use quads, but they're being phased out of OpenGL3, so we're using triangles instead)
GLuint vboID; // Vertex Buffer Object ID
GLuint indexVBOID; // Index Buffer Object ID
float angle = 0.0; // Just for display rotation

int main (int argc, char * argv[]) 
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(320, 320);
    glutCreateWindow("VBO Example");
    //glutFullScreen();
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutReshapeFunc(changeSize);
    glutKeyboardFunc(processNormalKeys);
    glEnable(GL_DEPTH_TEST);
    buildCube();
    glewInit();
    initVBO();  
    glMatrixMode(GL_PROJECTION);
    gluLookAt(0.0, 0.0, 5.0,
              0.0, 0.0, -1.0,
              0.0, 1.0, 0.0);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glutMainLoop();
    return 0;
}

void renderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    initVBO();
    glPushMatrix();
    glRotatef(angle, 1.0, 1.0, 1.0);

    // Bind our buffers much like we would for texturing
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBOID);
    void* b= glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
    for(int i=0;i<24;i++)
    {
        Vertex* v= &verts[i];
        v->location[X_POS]*=INC_SCALE;
        v->location[Y_POS]*=INC_SCALE;
        v->location[Z_POS]*=INC_SCALE;
    }
    memcpy(b, verts, 24*sizeof(Vertex));
    glUnmapBuffer(GL_ARRAY_BUFFER);
    // Set the state of what we are drawing (I don't think order matters here, but I like to do it in the same 
    // order I set the pointers
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    // Resetup our pointers.  This doesn't reinitialise any data, only how we walk through it
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
    glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
    glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

    // Actually do our drawing, parameters are Primative (Triangles, Quads, Triangle Fans etc), Elements to 
    // draw, Type of each element, Start Offset
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

    // Disable our client state back to normal drawing
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glPopMatrix();
    glutSwapBuffers();
    angle += 0.01;
}

void changeSize(int w, int h)
{
    if (h == 0) // Prevent divide by zero
        h = 1;

    float ratio = 1.0 * w / h;
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);


    glViewport(0, 0, w, h);

    gluPerspective(45, ratio, 1, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0,
              0.0, 0.0, -1.0,
              0.0, 1.0, 0.0);

}

void processNormalKeys(unsigned char key, int x, int y)
{
    if (key == 27)
        exit(0);
}

void initVBO()
{
    glGenBuffers(1, &vboID); // Create the buffer ID, this is basically the same as generating texture ID's
    glBindBuffer(GL_ARRAY_BUFFER, vboID); // Bind the buffer (vertex array data)

    // Allocate space.  We could pass the mesh in here (where the NULL is), but it's actually faster to do it as a 
    // seperate step.  We also define it as GL_STATIC_DRAW which means we set the data once, and never 
    // update it.  This is not a strict rule code wise, but gives hints to the driver as to where to store the data 
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 24, NULL, GL_STREAM_DRAW);
    //glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * 24, verts);



    // Set the pointers to our data.  Except for the normal value (which always has a size of 3), we must pass 
    // the size of the individual component.  ie. A vertex has 3 points (x, y, z), texture coordinates have 2 (u, v) etc.
    // Basically the arguments are (ignore the first one for the normal pointer), Size (many components to 
    // read), Type (what data type is it), Stride (how far to move forward - in bytes - per vertex) and Offset 
    // (where in the buffer to start reading the data - in bytes)

    // Make sure you put glVertexPointer at the end as there is a lot of work that goes on behind the scenes
    // with it, and if it's set at the start, it has to do all that work for each gl*Pointer call, rather than once at
    // the end. 
    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
    glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
    glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

    // When we get here, all the vertex data is effectively on the card

    glGenBuffers(1, &indexVBOID); // Generate buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBOID); // Bind the element array buffer
    // Upload the index array, this can be done the same way as above (with NULL as the data, then a 
    // glBufferSubData call, but doing it all at once for convenience)  
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36 * sizeof(GLubyte), index, GL_STATIC_DRAW);
}

void buildCube()
{
    // Ugh, ugly code this

    // Top

    verts[0].location[X_POS]    = 1;    verts[0].location[Y_POS]    = 1;    verts[0].location[Z_POS]    = -1;
    verts[0].normal[X_POS]      = 0;    verts[0].normal[Y_POS]      = 1;    verts[0].normal[Z_POS]      = 0;
    verts[0].tex[U_POS]         = 0;    verts[0].tex[V_POS]         = 0; 


    verts[1].location[X_POS]    = -1;   verts[1].location[Y_POS]    = 1;    verts[1].location[Z_POS]    = -1;
    verts[1].normal[X_POS]      = 0;    verts[1].normal[Y_POS]      = 1;    verts[1].normal[Z_POS]      = 0;
    verts[1].tex[U_POS]         = 0;    verts[1].tex[V_POS]         = 1; 

    verts[2].location[X_POS]    = -1;   verts[2].location[Y_POS]    = 1;    verts[2].location[Z_POS]    = 1;
    verts[2].normal[X_POS]      = 0;    verts[2].normal[Y_POS]      = 1;    verts[2].normal[Z_POS]      = 0;
    verts[2].tex[U_POS]         = 1;    verts[2].tex[V_POS]         = 1; 

    verts[3].location[X_POS]    = 1;    verts[3].location[Y_POS]    = 1;    verts[3].location[Z_POS]    = 1;
    verts[3].normal[X_POS]      = 0;    verts[3].normal[Y_POS]      = 1;    verts[3].normal[Z_POS]      = 0;
    verts[3].tex[U_POS]         = 1;    verts[3].tex[V_POS]         = 0;

    // Bottom
    verts[4].location[X_POS]    = 1;    verts[4].location[Y_POS]    = -1;   verts[4].location[Z_POS]    = 1;
    verts[4].normal[X_POS]      = 0;    verts[4].normal[Y_POS]      = -1;   verts[4].normal[Z_POS]      = 0;
    verts[4].tex[U_POS]         = 0;    verts[4].tex[V_POS]         = 0; 

    verts[5].location[X_POS]    = -1;   verts[5].location[Y_POS]    = -1;   verts[5].location[Z_POS]    = 1;
    verts[5].normal[X_POS]      = 0;    verts[5].normal[Y_POS]      = -1;   verts[5].normal[Z_POS]      = 0;
    verts[5].tex[U_POS]         = 0;    verts[5].tex[V_POS]         = 1; 

    verts[6].location[X_POS]    = -1;   verts[6].location[Y_POS]    = -1;   verts[6].location[Z_POS]    = -1;
    verts[6].normal[X_POS]      = 0;    verts[6].normal[Y_POS]      = -1;   verts[6].normal[Z_POS]      = 0;
    verts[6].tex[U_POS]         = 1;    verts[6].tex[V_POS]         = 1; 

    verts[7].location[X_POS]    = 1;    verts[7].location[Y_POS]    = -1;   verts[7].location[Z_POS]    = -1;
    verts[7].normal[X_POS]      = 0;    verts[7].normal[Y_POS]      = -1;   verts[7].normal[Z_POS]      = 0;
    verts[7].tex[U_POS]         = 1;    verts[7].tex[V_POS]         = 0;

    // Front
    verts[8].location[X_POS]    = 1;    verts[8].location[Y_POS]    = 1;    verts[8].location[Z_POS]    = 1;
    verts[8].normal[X_POS]      = 0;    verts[8].normal[Y_POS]      = 0;    verts[8].normal[Z_POS]      = 1;
    verts[8].tex[U_POS]         = 0;    verts[8].tex[V_POS]         = 0; 

    verts[9].location[X_POS]    = -1;   verts[9].location[Y_POS]    = 1;    verts[9].location[Z_POS]    = 1;
    verts[9].normal[X_POS]      = 0;    verts[9].normal[Y_POS]      = 0;    verts[9].normal[Z_POS]      = 1;
    verts[9].tex[U_POS]         = 0;    verts[9].tex[V_POS]         = 1; 

    verts[10].location[X_POS]   = -1;   verts[10].location[Y_POS]   = -1;   verts[10].location[Z_POS]   = 1;
    verts[10].normal[X_POS]     = 0;    verts[10].normal[Y_POS]     = 0;    verts[10].normal[Z_POS]     = 1;
    verts[10].tex[U_POS]        = 1;    verts[10].tex[V_POS]        = 1; 

    verts[11].location[X_POS]   = 1;    verts[11].location[Y_POS]   = -1;   verts[11].location[Z_POS]   = 1;
    verts[11].normal[X_POS]     = 0;    verts[11].normal[Y_POS]     = 0;    verts[11].normal[Z_POS]     = 1;
    verts[11].tex[U_POS]        = 1;    verts[11].tex[V_POS]        = 0;

    // Back
    verts[12].location[X_POS]   = 1;    verts[12].location[Y_POS]   = -1;   verts[12].location[Z_POS]   = -1;
    verts[12].normal[X_POS]     = 0;    verts[12].normal[Y_POS]     = 0;    verts[12].normal[Z_POS]     = -1;
    verts[12].tex[U_POS]        = 0;    verts[12].tex[V_POS]        = 0; 

    verts[13].location[X_POS]   = -1;   verts[13].location[Y_POS]   = -1;   verts[13].location[Z_POS]   = -1;
    verts[13].normal[X_POS]     = 0;    verts[13].normal[Y_POS]     = 0;    verts[13].normal[Z_POS]     = -1;
    verts[13].tex[U_POS]        = 0;    verts[13].tex[V_POS]        = 1; 

    verts[14].location[X_POS]   = -1;   verts[14].location[Y_POS]   = 1;    verts[14].location[Z_POS]   = -1;
    verts[14].normal[X_POS]     = 0;    verts[14].normal[Y_POS]     = 0;    verts[14].normal[Z_POS]     = -1;
    verts[14].tex[U_POS]        = 1;    verts[14].tex[V_POS]        = 1; 

    verts[15].location[X_POS]   = 1;    verts[15].location[Y_POS]   = 1;    verts[15].location[Z_POS]   = -1;
    verts[15].normal[X_POS]     = 0;    verts[15].normal[Y_POS]     = 0;    verts[15].normal[Z_POS]     = -1;
    verts[15].tex[U_POS]        = 1;    verts[15].tex[V_POS]        = 0;

    // Left
    verts[16].location[X_POS]   = -1;   verts[16].location[Y_POS]   = 1;    verts[16].location[Z_POS]   = 1;
    verts[16].normal[X_POS]     = -1;   verts[16].normal[Y_POS]     = 0;    verts[16].normal[Z_POS]     = 0;
    verts[16].tex[U_POS]        = 0;    verts[16].tex[V_POS]        = 0; 

    verts[17].location[X_POS]   = -1;   verts[17].location[Y_POS]   = 1;    verts[17].location[Z_POS]   = -1;
    verts[17].normal[X_POS]     = -1;   verts[17].normal[Y_POS]     = 0;    verts[17].normal[Z_POS]     = 0;
    verts[17].tex[U_POS]        = 0;    verts[17].tex[V_POS]        = 1; 

    verts[18].location[X_POS]   = -1;   verts[18].location[Y_POS]   = -1;   verts[18].location[Z_POS]   = -1;
    verts[18].normal[X_POS]     = -1;   verts[18].normal[Y_POS]     = 0;    verts[18].normal[Z_POS]     = 0;
    verts[18].tex[U_POS]        = 1;    verts[18].tex[V_POS]        = 1; 

    verts[19].location[X_POS]   = -1;   verts[19].location[Y_POS]   = -1;   verts[19].location[Z_POS]   = 1;
    verts[19].normal[X_POS]     = -1;   verts[19].normal[Y_POS]     = 0;    verts[19].normal[Z_POS]     = 0;
    verts[19].tex[U_POS]        = 1;    verts[19].tex[V_POS]        = 0;

    // Right
    verts[20].location[X_POS]   = 1;    verts[20].location[Y_POS]   = 1;    verts[20].location[Z_POS]   = -1;
    verts[20].normal[X_POS]     = 1;    verts[20].normal[Y_POS]     = 0;    verts[20].normal[Z_POS]     = 0;
    verts[20].tex[U_POS]        = 0;    verts[20].tex[V_POS]        = 0; 

    verts[21].location[X_POS]   = 1;    verts[21].location[Y_POS]   = 1;    verts[21].location[Z_POS]   = 1;
    verts[21].normal[X_POS]     = 1;    verts[21].normal[Y_POS]     = 0;    verts[21].normal[Z_POS]     = 0;
    verts[21].tex[U_POS]        = 0;    verts[21].tex[V_POS]        = 1; 

    verts[22].location[X_POS]   = 1;    verts[22].location[Y_POS]   = -1;   verts[22].location[Z_POS]   = 1;
    verts[22].normal[X_POS]     = 1;    verts[22].normal[Y_POS]     = 0;    verts[22].normal[Z_POS]     = 0;
    verts[22].tex[U_POS]        = 1;    verts[22].tex[V_POS]        = 1; 

    verts[23].location[X_POS]   = 1;    verts[23].location[Y_POS]   = -1;   verts[23].location[Z_POS]   = -1;
    verts[23].normal[X_POS]     = 1;    verts[23].normal[Y_POS]     = 0;    verts[23].normal[Z_POS]     = 0;
    verts[23].tex[U_POS]        = 1;    verts[23].tex[V_POS]        = 0;

    // Colours
    for (int i = 0; i < 24; i++)
    {
        verts[i].colour[R_POS] = 1.0;
        verts[i].colour[G_POS] = 1.0;
    //  verts[i].colour[B_POS] = 1.0;
        verts[i].colour[A_POS] = 1.0;
    }

    // Index Array (define our triangles)
    // A Face looks like (numbers are the array index number of the vertex)
    // 1      2
    // +------+
    // |      |
    // |      |
    // +------+
    // 0      3
    index[0] = 0;   index[1] = 1;   index[2] = 2;
    index[3] = 2;   index[4] = 3;   index[5] = 0;

    index[6] = 4;   index[7] = 5;   index[8] = 6;
    index[9] = 6;   index[10] = 7;  index[11] = 4;

    index[12] = 8;  index[13] = 9;  index[14] = 10;
    index[15] = 10; index[16] = 11; index[17] = 8;

    index[18] = 12; index[19] = 13; index[20] = 14;
    index[21] = 14; index[22] = 15; index[23] = 12;

    index[24] = 16; index[25] = 17; index[26] = 18;
    index[27] = 18; index[28] = 19; index[29] = 16;

    index[30] = 20; index[31] = 21; index[32] = 22;
    index[33] = 22; index[34] = 23; index[35] = 20;

}
Mat
  • 202,337
  • 40
  • 393
  • 406
prongs
  • 9,422
  • 21
  • 67
  • 105
  • 4
    You put up too much code, you are using deprecated functions, the solution is easily googlable and there are a lot of tutorials. My job here is done. – Bartek Banachewicz Aug 14 '12 at 11:26
  • can you atleast make a suggestion? – prongs Aug 14 '12 at 13:02
  • 4
    Make a good reading about the topic, try some of the solutions yourself, then come here with the subjects NOT covered by tutorial. And when you'll back, don't post your whole code, but only the relevant part. Try arcsynthesis.org/gltut – Bartek Banachewicz Aug 14 '12 at 13:23

0 Answers0