由于《OpenGL ES 2.0 Programming Guide》原书并没有提供第8章的关于VBO的示例代码,书上的代码也只提到关键的步骤,网上的例子大都不够精简,为了加深理解,遂自己实现了一份最简单的C语言版本,希望能够帮助到同样喜欢OpenGL ES 2.0的同学。
废话不多说,直接上代码:
#include "esUtil.h"
typedef struct
{
// Handle to a program object
GLuint programObject;
GLint positionLoc;
GLint colorLoc;
// VertexBufferObject Ids
GLuint vboIds[3];
} UserData;
#define VERTEX_POS_SIZE 3 // x, y and z
#define VERTEX_COLOR_SIZE 4 // r, g, b, and a
int Init ( ESContext *esContext )
{
UserData *userData = esContext->userData;
const char vShaderStr[] =
"attribute vec3 a_position; \n"
"attribute vec4 a_color; \n"
"varying vec4 v_color; \n"
"void main() \n"
"{ \n"
" v_color = a_color; \n"
" gl_Position = vec4(a_position, 1.0); \n"
"} \n";
const char fShaderStr[] =
"precision mediump float; \n"
"varying vec4 v_color; \n"
"void main() \n"
"{ \n"
" gl_FragColor = v_color; \n"
"} \n" ;
GLuint programObject;
// Create the program object
programObject = esLoadProgram ( vShaderStr, fShaderStr );
if ( programObject == 0 )
{
return GL_FALSE;
}
// Store the program object
userData->programObject = programObject;
userData->vboIds[0] = 0;// pos
userData->vboIds[1] = 0;// color
userData->vboIds[2] = 0;// index
userData->positionLoc = glGetAttribLocation(userData->programObject, "a_position");
userData->colorLoc = glGetAttribLocation(userData->programObject, "a_color");
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
return GL_TRUE;
}
void DrawPrimitiveWithVBOs ( ESContext *esContext,
GLint numVertices, GLfloat *vertexPosBuf, GLfloat *vertexColorBuf,
GLint *vtxStrides, GLint numIndices,
GLushort *indices )
{
UserData *userData = esContext->userData;
// vboIds[0] - used to store vertex position
// vboIds[1] - used to store vertex color
// vboIds[2] - used to store element indices
// run only once
if ( userData->vboIds[0] == 0 && userData->vboIds[1] == 0 &&
userData->vboIds[2] == 0 )
{
// Only allocate on the first draw
glGenBuffers ( 3, userData->vboIds );
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] );
glBufferData ( GL_ARRAY_BUFFER, vtxStrides[0] * numVertices,
vertexPosBuf, GL_STATIC_DRAW );
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] );
glBufferData ( GL_ARRAY_BUFFER, vtxStrides[1] * numVertices,
vertexColorBuf, GL_STATIC_DRAW );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] );
glBufferData ( GL_ELEMENT_ARRAY_BUFFER,
sizeof ( GLushort ) * numIndices,
indices, GL_STATIC_DRAW );
}
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] );
glVertexAttribPointer ( userData->positionLoc,
VERTEX_POS_SIZE,
GL_FLOAT, GL_FALSE, vtxStrides[0], 0 );
glEnableVertexAttribArray ( userData->positionLoc );
glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] );
glVertexAttribPointer ( userData->colorLoc,
VERTEX_COLOR_SIZE,
GL_FLOAT, GL_FALSE, vtxStrides[1], 0 );
glEnableVertexAttribArray ( userData->colorLoc );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] );
glDrawElements ( GL_TRIANGLES, numIndices,
GL_UNSIGNED_SHORT, 0 );
eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); // ☆
// ---------------------------------------------------
glDisableVertexAttribArray ( userData->positionLoc );
glDisableVertexAttribArray ( userData->colorLoc );
glBindBuffer ( GL_ARRAY_BUFFER, 0 );
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
void Draw ( ESContext *esContext )
{
UserData *userData = esContext->userData;
// 3 vertices, with (x,y,z) ,(r, g, b, a) per-vertex
GLfloat vertexPos[3 * VERTEX_POS_SIZE] =
{
0.0f, 0.5f, 0.0f, // v0
-0.5f, -0.5f, 0.0f, // v1
0.5f, -0.5f, 0.0f // v2
};
GLfloat color[4 * VERTEX_COLOR_SIZE] =
{
1.0f, 0.0f, 0.0f, 1.0f, // c0
0.0f, 1.0f, 0.0f, 1.0f, // c1
0.0f, 0.0f, 1.0f, 1.0f // c2
};
GLint vtxStrides[2] =
{
VERTEX_POS_SIZE * sizeof ( GLfloat ),
VERTEX_COLOR_SIZE * sizeof ( GLfloat )
};
// Index buffer data
GLushort indices[3] = { 0, 1, 2 };
//GLfloat *vtxBuf[2] = { vertexPos, color };
glViewport ( 0, 0, esContext->width, esContext->height );
glClear ( GL_COLOR_BUFFER_BIT );
glUseProgram ( userData->programObject );
DrawPrimitiveWithVBOs ( esContext, 3, vertexPos, color,
vtxStrides, 3, indices );
}
void ShutDown ( ESContext *esContext )
{
UserData *userData = esContext->userData;
glDeleteProgram ( userData->programObject );
glDeleteBuffers ( 3, userData->vboIds );
}
int main ( int argc, char *argv[] )
{
ESContext esContext;
UserData userData;
esInitContext ( &esContext );
esContext.userData = &userData;
esCreateWindow ( &esContext, "SimpleVBO", 320, 240, ES_WINDOW_RGB );
if ( !Init ( &esContext ) )
{
return GL_FALSE;
}
esRegisterDrawFunc ( &esContext, Draw );
esMainLoop ( &esContext );
ShutDown ( &esContext );
return GL_TRUE;
}