In this tutorial I will show you now how to implement a vertex buffer object (or VBO) class.

Vertex Buffer Objects (VBOs) is an OpenGL extension very similar to Vertex Arrays (VA) that provides methods for uploading data
(vertices, texture coordinates etc) to the video device for non-immediate mode rendering.
We shall use VBO because it offers substantial performance gains over immediate mode and additional speed gain over VA.

VBOs are very similar to Vertex Arrays in code and principle, the main difference is that VA hold the data in RAM,
while VBOs hold the data into the video card memory making it faster to access.
VBOs are supported by hardware featuring OpenGL 1.5 and uses the ARB_vertex_buffer_object extension.

This class helps you render VBO more easy. It supports: vertices (points, line, line strips, triangles, triangle strips, quads and quad strips),
vertex normals, texture coordinates (for a single textures and only 2D textures), normal dataand color data.

///////////////////////////// CVBO.H FILE ///////////////////////////////

#ifndef _CVBO_H_
#define _CVBO_H_

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#include <gl\wglext.h>
#include "glext.h"

// ARB_vertex_buffer_object extension definition
PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;
PFNGLISBUFFERARBPROC glIsBufferARB = NULL;
PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;
PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL;
PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB = NULL;
PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;

// Texture coordinates structure
struct TextureCoordinates
{
float s;
float t;
} ;

// Vertex coordinates structure
struct VertexCoordinates
{
float x;
float y;
float z;
} ;

// Normal data coordinates structure
struct NormalData
{
float x;
float y;
float z;
} ;

// Color structure
struct ColorVBO
{
float fRed;
float fGreen;
float fBlue;
float fAlpha;
} ;

// Vertex Buffer Objects class
class CVertexBufferObjects
{
private:
// VBO texture coordinates data
GLuint m_uiTextCoordBuffer;
// VBO vertex data
GLuint m_uiVertexBuffer;
// VBO normal data
GLuint m_uiNormalBuffer;
// VBO color data
GLuint m_uiColorBuffer;
// The number of vertices
GLuint m_uiVertexNumber;

public:
// Default Constructor. Does nothing
CVertexBufferObjects() {};

// Copy Constructor. Initializes the VBO
// pTextCoordData is an array of texture coordinates
// pVertexData is an array of floats containing the data
// pNormalData is an array of floats containing the data
// pColorData is an array of floats containing the data
// uArraySize is the size of the arrays
// bIsDataStatic is the data is static of dynamic?
CVertexBufferObjects(TextureCoordinates pTextCoordData[], VertexCoordinates pVertexData[], NormalData pNormalData[],
ColorVBO pColorData[], const unsigned int& uArraySize, const bool& bIsDataStatic = false)
{
Initialize(pTextCoordData, pVertexData, pNormalData, pColorData, uArraySize, bIsDataStatic);
};

// Initializes the VBO
// pTextCoordData is an array of texture coordinates
// pVertexData is an array of floats containing the data
// pNormalData is an array of floats containing the data
// pColorData is an array of floats containing the data
// uArraySize is the size of the arrays
// bIsDataStatic is the data is static of dynamic?
void Initialize(TextureCoordinates pTextCoordData[], VertexCoordinates pVertexData[], NormalData pNormalData[],
ColorVBO pColorData[], const unsigned int& uArraySize, const bool& bIsDataStatic = false);

// Enable Pointers. Used before rendering the VBOs
void EnableClientState();

// Binds the buffers. Used before rendering the VBOs
void BindBuffer();

// Render the VBO data. In this case the data is an collection of points
inline void RenderPoints() const { glDrawArrays(GL_POINTS, 0, m_uiVertexNumber); };

// Render the VBO data. In this case the data is an collection of lines
inline void RenderLines() const { glDrawArrays(GL_LINES, 0, m_uiVertexNumber * 2); };

// Render the VBO data. In this case the data is an collection of line strips
inline void RenderLineStrip() const { glDrawArrays(GL_LINE_STRIP, 0, m_uiVertexNumber * 2); };

// Render the VBO data. In this case the data is an collection of triangles
inline void RenderTriangles() const { glDrawArrays(GL_TRIANGLES, 0, m_uiVertexNumber * 3); };

// Render the VBO data. In this case the data is an collection of triangle strips
inline void RenderTriangleStrip() const { glDrawArrays(GL_TRIANGLE_STRIP, 0, m_uiVertexNumber * 3); };

// Render the VBO data. In this case the data is an collection of quads
inline void RenderQuads() const { glDrawArrays(GL_QUADS, 0, m_uiVertexNumber * 4); };

// Render the VBO data. In this case the data is an collection of quad strips
inline void RenderQuadStrip() const { glDrawArrays(GL_QUAD_STRIP, 0, m_uiVertexNumber * 4); };

// Disable Pointers. Used after rendering the VBOs
void DisableClientState();

// Default Destructor. Deletes the VBO
~CVertexBufferObjects();
};

#endif

///////////////////////////// CVBO.CPP FILE ///////////////////////////////

#include "CVBO.h"

// Initializes the VBO
// pTextCoordData is an array of texture coordinates
// pVertexData is an array of floats containing the data
// pNormalData is an array of floats containing the data
// pColorData is an array of floats containing the data
// uArraySize is the size of the arrays
// bIsDataStatic is the data is static of dynamic?
void CVertexBufferObjects::Initialize(TextureCoordinates pTextCoordData[], VertexCoordinates pVertexData[],
NormalData pNormalData[], ColorVBO pColorData[],
const unsigned int& uArraySize, const bool& bIsDataStatic)
{
m_uiTextCoordBuffer = 0;
m_uiNormalBuffer = 0;
m_uiVertexBuffer = 0;
m_uiColorBuffer = 0;
m_uiVertexNumber = uArraySize;

char *strExtension = (char*) glGetString(GL_EXTENSIONS);

// If the videocard supports the VBO extension, loads the VBO extensions. If not the programm exits
if(strstr(strExtension, "ARB_vertex_buffer_object") != NULL)
{
// Gets the addresses of the VBO functions
glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB");
glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
glIsBufferARB = (PFNGLISBUFFERARBPROC) wglGetProcAddress("glIsBufferARB");
glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) wglGetProcAddress("glBufferSubDataARB");
glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) wglGetProcAddress("glGetBufferSubDataARB");
glMapBufferARB = (PFNGLMAPBUFFERARBPROC) wglGetProcAddress("glMapBufferARB");
glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) wglGetProcAddress("glUnmapBufferARB");
glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) wglGetProcAddress("glGetBufferParameterivARB");
glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) wglGetProcAddress("glGetBufferPointervARB");
}
else
{
MessageBox(NULL, "Doesn't support an extension! You might need to upgrade you'r video card! Program terminated!" ,"Error!", MB_OK | MB_ICONSTOP);
exit(0);
}

if (pColorData) // If we have color data, initializes it
{
glGenBuffersARB(1, &m_uiColorBuffer); // Generates the buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiColorBuffer); // Binds the generatad buffer
glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_uiVertexNumber*4*sizeof(float), pColorData, // Puts the data into the buffer
bIsDataStatic ? GL_STATIC_DRAW_ARB : GL_DYNAMIC_DRAW);
}

if (pTextCoordData) // If we have texture coordinates data, initializes it
{
glGenBuffersARB(1, &m_uiTextCoordBuffer); // Generates the buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiTextCoordBuffer); // Binds the generated buffer
glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_uiVertexNumber*2*sizeof(float), pTextCoordData, // Puts the data into the buffer
bIsDataStatic ? GL_STATIC_DRAW_ARB : GL_DYNAMIC_DRAW);
}

if (pNormalData) // If we have normal data, initializes it
{
glGenBuffersARB(1, &m_uiNormalBuffer); // Generates the buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiNormalBuffer); // Binds the generated buffer
glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_uiVertexNumber*3*sizeof(float), pNormalData, // Puts the data into the buffer
bIsDataStatic ? GL_STATIC_DRAW_ARB : GL_DYNAMIC_DRAW);
}

if (pVertexData) // If we have vertex data, initializes it
{
glGenBuffersARB(1, &m_uiVertexBuffer); // Generates the buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiVertexBuffer); // Binds the generated buffer
glBufferDataARB(GL_ARRAY_BUFFER_ARB, m_uiVertexNumber*3*sizeof(float), pVertexData, // Puts the data into the buffer
bIsDataStatic ? GL_STATIC_DRAW_ARB : GL_DYNAMIC_DRAW);
}
};

// Enable Pointers, but only if we are using this type of pointer. Used before rendering the VBOs
void CVertexBufferObjects::EnableClientState()
{
if (m_uiColorBuffer > 0)
glEnableClientState(GL_COLOR_ARRAY);
if (m_uiTextCoordBuffer > 0)
glEnableClientState(GL_VERTEX_ARRAY);
if (m_uiNormalBuffer > 0)
glEnableClientState(GL_NORMAL_ARRAY);
if (m_uiVertexBuffer > 0)
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
};

// Binds the buffers, but only if we are using this type of pointer. Used before rendering the VBOs
void CVertexBufferObjects::BindBuffer()
{
if (m_uiColorBuffer > 0)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiColorBuffer);
glColorPointer(4, GL_FLOAT, 0, (char*) NULL);
}

if (m_uiTextCoordBuffer > 0)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiTextCoordBuffer);
glTexCoordPointer(2, GL_FLOAT, 0, (char*) NULL);
}

if (m_uiNormalBuffer)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiNormalBuffer);
glNormalPointer(GL_FLOAT, 0, (char*) NULL);
}

if (m_uiVertexBuffer > 0)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_uiVertexBuffer);
glVertexPointer(3, GL_FLOAT, 0, (char*) NULL);
}
};

// Disable Pointers, but only if we are using this type of pointer. Used after rendering the VBOs
void CVertexBufferObjects::DisableClientState()
{
if (m_uiColorBuffer > 0)
glDisableClientState(GL_COLOR_ARRAY);
if (m_uiTextCoordBuffer > 0)
glDisableClientState(GL_VERTEX_ARRAY);
if (m_uiNormalBuffer > 0)
glDisableClientState(GL_NORMAL_ARRAY);
if (m_uiVertexBuffer > 0)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
};

// Default Destructor, but only if we are using this type of pointer. Deletes the VBO
CVertexBufferObjects::~CVertexBufferObjects()
{
glBindBufferARB(GL_ARRAY_BUFFER, 0);

if (m_uiColorBuffer > 0)
glDeleteBuffersARB(1, &m_uiColorBuffer); // Deletes the color data buffer
if (m_uiTextCoordBuffer > 0)
glDeleteBuffersARB(1, &m_uiTextCoordBuffer); // Deletes the texture coordinates data buffer
if (m_uiNormalBuffer > 0)
glDeleteBuffersARB(1, &m_uiNormalBuffer); // Deletes the normal data buffer
if (m_uiVertexBuffer > 0)
glDeleteBuffersARB(1, &m_uiVertexBuffer); // Deletes the vertex data buffer
};

 

The class will be used:
Initialization:
- creates an pointer to a structure of the data type(s) we want (vertex, normal etc);
- we initialize the created structures with the data we want;
- we initialize the VBO with the structures we just created with the "Initialize" function;
- now we can delete the structures we created earlier because we bind them into the VBO;
Rendering:
- we call the EnableClientState function;
- we call the BindBuffer function;
- we call one or the 7 rendering functions;
- we call DisableClientState function;

So we reach the end of this tutorial. I hope you enjoy reading it and that you learned something from it.
I have some suggestions for improving this VBO class:
- add support for multitexturing (multiple texture coordinates);
- add support for other texture types (1D and 3D);

Well If you have any questions, suggestions, you found some mistakes in this tutorial or you know a better way to do some thing,
please mail me at liviuemanuel@yahoo.com


Download the files