天天看点

《OpenGL ES 2.0 Programming Guide》第8章 “最简单的Vertex Buffer Object”示例代码【C语言版】

由于《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;
}      

继续阅读