《OpenGL ES 2.0 Programming Guide》第12章 “最简单的本地纹理+FBO+VBO”示例代码【C语言版】

来源:互联网 发布:网络歌曲磨剪子抢菜刀 编辑:程序博客网 时间:2024/06/14 19:17

由于《OpenGL ES 2.0 Programming Guide》原书第12章并没有提供相关的示例,为了加深理解,遂自己实现了一份C语言版本作为练习,希望能够帮助到同样喜欢OpenGL ES 2.0的同学。


废话不多说,直接上代码:


#include <stdlib.h>#include <stdio.h>#include "esUtil.h"#include "userData.h"#define SIZE 512///// Load texture from disk//GLuint LoadTexture ( char *fileName ){    int width, height;    char *buffer = esLoadTGA ( fileName, &width, &height );    GLuint texId;    if ( buffer == NULL )    {        esLogMessage ( "Error loading (%s) image.\n", fileName );        return 0;    }    glGenTextures ( 1, &texId );    glBindTexture ( GL_TEXTURE_2D, texId );    glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );    free ( buffer );    return texId;}int initFBO(ESContext *esContext, GLint width, GLint height){    GLenum status;    GLint maxRenderbufferSize;    UserData *userData = (UserData *)esContext->userData;    glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize);    // check if GL_MAX_RENDERBUFFER_SIZE is >= texWidth and texHeight    if ((maxRenderbufferSize <= width) || (maxRenderbufferSize <= height))    {        // cannot use framebuffer objects as we need to create        // a depth buffer as a renderbuffer object        printf("Cannot use framebuffer objects!\n");        exit(EXIT_FAILURE);        return FALSE;    }    // generate the framebuffer, renderbuffer names    glGenFramebuffers(1, &userData->frameBuffer);    glGenRenderbuffers(1, &userData->depthRenderBuffer);    // bind renderbuffer and create a 16-bit depth buffer    // width and height of renderbuffer = width and height of    // the texture    glBindRenderbuffer(GL_RENDERBUFFER, userData->depthRenderBuffer);    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);    // Texture    glGenTextures(1, &userData->textureId);    glBindTexture(GL_TEXTURE_2D, userData->textureId);    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,                 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );    // bind the framebuffer    glBindFramebuffer(GL_FRAMEBUFFER, userData->frameBuffer);    // ☆ specify texture as color attachment ☆    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, userData->textureId, 0);    // specify depth_renderbufer as depth attachment    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, userData->depthRenderBuffer);    // check for framebuffer complete    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);    if (status != GL_FRAMEBUFFER_COMPLETE)    {        printf("Framebuffer object is not complete!\n");        exit(EXIT_FAILURE);        return FALSE;    }    //glBindFramebuffer(GL_FRAMEBUFFER, 0);    return TRUE;}int InitFBOShader(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    const char vShaderStr[] =        "attribute vec4 a_position;\n"        "attribute vec2 a_texCoord;\n"        "varying vec2 v_texCoord;\n"        "void main()\n"        "{\n"        "   gl_Position = a_position;\n"        "   v_texCoord = a_texCoord;\n"        "}\n";    const char fShaderStr[] =        "precision mediump float;\n"        "varying vec2 v_texCoord;\n"        "uniform sampler2D s_texture;\n"        "const vec2 texSize = vec2(640., 640.);\n"        "const vec2 mosaicSize = vec2(16., 16.);\n"        "void main()\n"        "{\n"        "  vec4 color;\n"        "  vec2 xy = vec2(v_texCoord.x * texSize.x, v_texCoord.y * texSize.y);\n"        "  vec2 xyMosaic = vec2(floor(xy.x / mosaicSize.x) * mosaicSize.x,\n"        "       floor(xy.y / mosaicSize.y) * mosaicSize.y );\n"        "  //第几块mosaic\n"        "  vec2 xyFloor = vec2(floor(mod(xy.x, mosaicSize.x)),\n"        "       floor(mod(xy.y, mosaicSize.y)));\n"        "  vec2 uvMosaic = vec2(xyMosaic.x / texSize.x, xyMosaic.y / texSize.y);\n"        "  color = texture2D( s_texture, uvMosaic );\n"        "  gl_FragColor = color;\n"        "}\n";    userData->programFBOObject = esLoadProgram(vShaderStr, fShaderStr);    // Bind vPosition to attribute 0    //glBindAttribLocation(userData->programFBOObject, 0, "a_position");    userData->positionFBOLoc = glGetAttribLocation ( userData->programFBOObject, "a_position" );    userData->mvpFBOLoc = glGetUniformLocation( userData->programFBOObject, "u_mvpMatrix" );    userData->texcoordFBOLoc = glGetAttribLocation(userData->programFBOObject, "a_texCoord");    userData->samplerFBOLoc = glGetUniformLocation(userData->programFBOObject, "s_texture");    // Load the texture ☆    userData->textureFBOId = LoadTexture("../beard.tga");    // VBO Id    userData->vboFBOIds[0] = 0;    userData->vboFBOIds[1] = 0;    return TRUE;}int initShader(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    const char vShaderStr[] =        "uniform mat4 u_mvpMatrix;                   \n"        "attribute vec4 a_position;                  \n"        "attribute vec2 a_texCoord;                  \n"        "varying vec2 v_texCoord;                    \n"        "void main()                                 \n"        "{                                           \n"        "   gl_Position = u_mvpMatrix * a_position;  \n"        "   v_texCoord = a_texCoord;                 \n"        "}                                           \n";    const char fShaderStr[] =        "precision mediump float;                            \n"        "varying vec2 v_texCoord;                            \n"        "uniform sampler2D s_texture;                        \n"        "void main()                                         \n"        "{                                                   \n"        "  vec4 color = texture2D(s_texture, v_texCoord);    \n"        "  gl_FragColor = color;                             \n"        "}                                                   \n";    // Load the shaders and get a linked program object    userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );    // Get the attribute locations    userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );    // Get the uniform locations    userData->mvpLoc = glGetUniformLocation( userData->programObject, "u_mvpMatrix" );    // Get the texture  attribute locations    userData->texcoordLoc = glGetAttribLocation(userData->programObject, "a_texCoord");    userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");    // VBO Id    userData->vboIds[0] = 0;    userData->vboIds[1] = 0;    userData->vboIds[2] = 0;    return TRUE;}int Init(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    if (!InitFBOShader(esContext))    {        printf("initFBOShader exception ! \n");        return FALSE;    }    if (!initShader(esContext))    {        printf("initShader exception ! \n");        return FALSE;    }    initFBO(esContext, SIZE, SIZE);    // Generate the vertex data    userData->numIndices = esGenCube( 1.0, &userData->vertices,                                      NULL, &userData->texcoords, &userData->indices );    // Starting rotation angle for the cube    userData->angle = 45.0f;    glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );    glClearDepthf( 1.0f );    glEnable(GL_DEPTH_TEST);    glEnable(GL_CULL_FACE);    //glEnable(GL_BLEND);    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);    return TRUE;}// Update the mvp matrixvoid Update(ESContext *esContext, float deltaTime){    UserData *userData = (UserData *) esContext->userData;    ESMatrix perspective;    ESMatrix modelview;    float    aspect;    // Compute a rotation angle based on time to rotate the cube    userData->angle += ( deltaTime * 40.0f );    if( userData->angle >= 360.0f )        userData->angle -= 360.0f;    // Compute the window aspect ratio    aspect = (GLfloat) esContext->width / (GLfloat) esContext->height;    // Generate a perspective matrix with a 60 degree FOV    esMatrixLoadIdentity( &perspective );    esPerspective( &perspective, 60.0f, aspect, 1.0f, 20.0f );    // Generate a model view matrix to rotate/translate the cube    esMatrixLoadIdentity( &modelview );    // Translate away from the viewer    esTranslate( &modelview, 0.0, 0.0, -2.0 );    // Rotate the cube    esRotate( &modelview, userData->angle, 1.0, 0.0, 1.0 );    // Compute the final MVP by multiplying the    // modevleiw and perspective matrices together    esMatrixMultiply( &userData->mvpMatrix, &modelview, &perspective );}void DrawToFBO(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    const GLfloat vVertices[] =    {        -1.f,  1.f, 0.0f,// Position 0        0.0f,  0.0f,        // TexCoord 0        -1.f, -1.f, 0.0f,// Position 1        0.0f,  1.0f,        // TexCoord 1        1.f, -1.f, 0.0f,// Position 2        1.0f,  1.0f,        // TexCoord 2        1.f,  1.f, 0.0f,// Position 3        1.0f,  0.0f         // TexCoord 3    };    const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };    const int numIndices = 6;    const int numVertices = 4;    glBindFramebuffer(GL_FRAMEBUFFER, userData->frameBuffer);    // ----------------------------------------------------------    // Set the viewport    glViewport ( 0, 0, esContext->width, esContext->height );    // Clear the color buffer    glClearColor ( 1.0f, 1.0f, 1.0f, 1.0f );    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Use the program object    glUseProgram ( userData->programFBOObject );    // ----------------------------------------------------------    // Setup VBO    if(userData->vboFBOIds[0] == 0 &&            userData->vboFBOIds[1] == 0)    {        // Only allocate on the first draw        glGenBuffers ( 2, userData->vboFBOIds );        glBindBuffer ( GL_ARRAY_BUFFER, userData->vboFBOIds[0] );        glBufferData ( GL_ARRAY_BUFFER, (3 + 2) * sizeof(GLfloat) * numVertices,                       vVertices, GL_STATIC_DRAW );        glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboFBOIds[1] );        glBufferData ( GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(GLushort),                       indices, GL_STATIC_DRAW );    }    // -----------------------------------------------------------    // Load the vertex position    //glVertexAttribPointer ( userData->positionFBOLoc, 3, GL_FLOAT,    //GL_FALSE, 5 * sizeof(GLfloat), vVertices);    glBindBuffer ( GL_ARRAY_BUFFER, userData->vboFBOIds[0] );    glVertexAttribPointer ( userData->positionFBOLoc, 3, GL_FLOAT,                            GL_FALSE, (3 + 2) * sizeof(GLfloat), 0 );    glEnableVertexAttribArray ( userData->positionFBOLoc );    // -----------------------------------------------------------    // Load the texture coordinate    //glVertexAttribPointer(userData->texcoordFBOLoc, 2, GL_FLOAT,    //GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]);    glBindBuffer ( GL_ARRAY_BUFFER, userData->vboFBOIds[0] );    glVertexAttribPointer ( userData->texcoordFBOLoc, 2, GL_FLOAT,                            GL_FALSE, (3 + 2) * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));    glEnableVertexAttribArray(userData->texcoordFBOLoc);    // -----------------------------------------------------------    // Bind the FBO texture    // Set the sampler texture unit to 0    glActiveTexture(GL_TEXTURE0);    glBindTexture(GL_TEXTURE_2D, userData->textureFBOId);    glUniform1i(userData->samplerFBOLoc, 0);    // -----------------------------------------------------------    // Draw the quad    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboFBOIds[1] );    //glDrawElements ( GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices );    glDrawElements ( GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0 );    // -----------------------------------------------------------    // Clean    glBindTexture(GL_TEXTURE_2D, 0);    glBindBuffer ( GL_ARRAY_BUFFER, 0 );    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );    glDisableVertexAttribArray ( userData->positionFBOLoc );    glDisableVertexAttribArray ( userData->texcoordFBOLoc );}void Draw(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    DrawToFBO(esContext);    glBindFramebuffer(GL_FRAMEBUFFER, 0);    // ----------------------------------------------------------    // Set the viewport    glViewport ( 0, 0, esContext->width, esContext->height );    // Clear the color buffer    glClearColor (0.0f, 0.0f, 0.0f, 0.0f);    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Use the program object    glUseProgram ( userData->programObject );    // ----------------------------------------------------------    const int numVertices = 24;    // Setup VBO    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, 3 * sizeof(GLfloat) * numVertices,                       userData->vertices, GL_STATIC_DRAW );        glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] );        glBufferData ( GL_ARRAY_BUFFER, 2 * sizeof(GLfloat) * numVertices,                       userData->texcoords, GL_STATIC_DRAW );        glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] );        glBufferData ( GL_ELEMENT_ARRAY_BUFFER, userData->numIndices * sizeof(GLuint),                       userData->indices, GL_STATIC_DRAW );    }    // -----------------------------------------------------------    // Load the vertex position    //glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,    //GL_FALSE, 3 * sizeof(GLfloat), userData->vertices );    glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] );    glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,                            GL_FALSE, 3 * sizeof(GLfloat), 0 );    glEnableVertexAttribArray ( userData->positionLoc );    // -----------------------------------------------------------    // Load the texture coordinate    //glVertexAttribPointer(userData->texcoordLoc, 2, GL_FLOAT,    //GL_FALSE, 2 * sizeof(GLfloat), userData->texcoords);    glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] );    glVertexAttribPointer(userData->texcoordLoc, 2, GL_FLOAT,                          GL_FALSE, 2 * sizeof(GLfloat), 0);    glEnableVertexAttribArray(userData->texcoordLoc);    // -----------------------------------------------------------    // Load the MVP matrix    glUniformMatrix4fv( userData->mvpLoc, 1, GL_FALSE,                        (GLfloat *) &userData->mvpMatrix.m[0][0] );    // -----------------------------------------------------------    // Bind the new texture    // Set the sampler texture unit to 0    glActiveTexture(GL_TEXTURE0);    glBindTexture(GL_TEXTURE_2D, userData->textureId);    glUniform1i(userData->samplerLoc, 0);    // -----------------------------------------------------------    // Draw the cube    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] );    //glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices );    glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, 0 );    eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );    // -----------------------------------------------------------    // Unbind the texture    glBindTexture(GL_TEXTURE_2D, 0);    glBindBuffer ( GL_ARRAY_BUFFER, 0 );    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );    glDisableVertexAttribArray ( userData->positionLoc );    glDisableVertexAttribArray ( userData->texcoordLoc );}void ShutDown(ESContext *esContext){    UserData *userData = (UserData *)esContext->userData;    //glDisable(GL_BLEND);    if ( userData->vertices != NULL )    {        free ( userData->vertices );    }    if ( userData->texcoords != NULL )    {        free ( userData->texcoords );    }    if ( userData->indices != NULL )    {        free ( userData->indices );    }    // Delete program object    glDeleteProgram (userData->programObject);    glDeleteProgram(userData->programFBOObject);    // Delete texture    glDeleteTextures(1, &userData->textureId);    glDeleteTextures(1, &userData->textureFBOId);    glDeleteRenderbuffers(1, &userData->depthRenderBuffer);    glDeleteFramebuffers(1, &userData->frameBuffer);    // Delete VBO    glDeleteBuffers ( 2, userData->vboFBOIds );    glDeleteBuffers ( 3, userData->vboIds );}int main ( int argc, char *argv[] ){    ESContext esContext;    UserData  userData;    esInitContext ( &esContext );    esContext.userData = &userData;    esCreateWindow ( &esContext, "Simple FBO", SIZE, SIZE, ES_WINDOW_RGB | ES_WINDOW_MULTISAMPLE );    if ( !Init ( &esContext ) )        return 0;    esRegisterDrawFunc ( &esContext, Draw );    esRegisterUpdateFunc ( &esContext, Update );    esMainLoop ( &esContext );    ShutDown ( &esContext );}

效果图:




0 0
原创粉丝点击