标签:test awt glin lte 语言 memset argv raw fbi
由于《OpenGL ES 2.0 Programming Guide》原书并没有提供第12章的示例代码,书上的代码也只提到关键的步骤,而网上大多是Android/iOS版本的示例,C/C++的大都基于OpenGL或OpenGL ES 3.0,为了加深理解,遂自己实现了一份C语言版本的,希望能够帮助到同样喜欢OpenGL ES 2.0的同学。废话不多说,直接上代码
#include "stdafx.h" #include "esUtil.h" #include <stdlib.h> #include <stdio.h> #define SIZE 512 typedef struct { GLuint programFBOObject; GLuint programObject; GLuint texture; GLuint frameBuffer; GLuint depthRenderBuffer; GLint positionFBOLoc; GLint mvpFBOLoc; GLint positionLoc; GLint mvpLoc; GLint texcoordLoc; GLint samplerLoc; GLfloat *vertices; GLfloat *texcoords; GLuint *indices; int numIndices; GLfloat angle; ESMatrix mvpMatrix; } UserData; 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->texture); glBindTexture(GL_TEXTURE_2D, userData->texture); 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_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //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->texture, 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[] = "uniform mat4 u_mvpMatrix; \n" "attribute vec4 a_position; \n" "void main() \n" "{ \n" " gl_Position = u_mvpMatrix * a_position; \n" "} \n"; const char fShaderStr[] = "precision mediump float; \n" "void main() \n" "{ \n" " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n" "} \n"; userData->programFBOObject = esLoadProgram(vShaderStr, fShaderStr); if (!userData->programFBOObject) return FALSE; // 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" ); 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"); 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); return TRUE; } // Update the mvp matrix void 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; 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 ); // ----------------------------------------------------------- // Load the vertex position glVertexAttribPointer ( userData->positionFBOLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), userData->vertices ); glEnableVertexAttribArray ( userData->positionFBOLoc ); // ----------------------------------------------------------- // Load the texture coordinate //glVertexAttribPointer(userData->texcoordLoc, 2, GL_FLOAT, // GL_FALSE, 2 * sizeof(GLfloat), userData->texcoords); //glEnableVertexAttribArray(userData->texcoordLoc); // ----------------------------------------------------------- // Load the MVP matrix glUniformMatrix4fv( userData->mvpFBOLoc, 1, GL_FALSE, (GLfloat *) &userData->mvpMatrix.m[0][0] ); // ----------------------------------------------------------- // Draw the cube glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices ); } 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 ); // ----------------------------------------------------------- // Load the vertex position glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), userData->vertices ); glEnableVertexAttribArray ( userData->positionLoc ); // ----------------------------------------------------------- // Load the texture coordinate glVertexAttribPointer(userData->texcoordLoc, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), userData->texcoords); glEnableVertexAttribArray(userData->texcoordLoc); // ----------------------------------------------------------- // Load the MVP matrix glUniformMatrix4fv( userData->mvpLoc, 1, GL_FALSE, (GLfloat *) &userData->mvpMatrix.m[0][0] ); // ----------------------------------------------------------- // Bind the texture // Set the sampler texture unit to 0 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, userData->texture); glGenerateMipmap(GL_TEXTURE_2D); glUniform1i(userData->samplerLoc, 0); // ----------------------------------------------------------- // Draw the cube glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices ); eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); glBindTexture(GL_TEXTURE_2D, 0); } void ShutDown(ESContext *esContext) { UserData *userData = (UserData *)esContext->userData; 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->texture); glDeleteRenderbuffers(1, &userData->depthRenderBuffer); glDeleteFramebuffers(1, &userData->frameBuffer); } BOOL SaveBMP(const char *lpFileName) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); int width = viewport[2]; int height = viewport[3]; glPixelStorei(GL_PACK_ALIGNMENT, 4); int nAlignWidth = (width * 24 + 31) / 32; unsigned char *pdata = new unsigned char[nAlignWidth * height * 4]; memset(pdata, 0, nAlignWidth * height * 4); // 从当前绑定的 frame buffer 读取 pixels glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pdata); //由RGB变BGR for(int i = 0 ; i < width * height * 3 ; i += 3) { unsigned char tmpRGB; tmpRGB = pdata[i]; pdata[i] = pdata[i + 2]; pdata[i + 2] = tmpRGB; } ////四字节对齐 //int nAlignWidth = (width*24+31)/32; //unsigned char *pDataAfterAlign = (unsigned char *) malloc(4 * nAlignWidth * height); //memset(pDataAfterAlign, 0, 4 * nAlignWidth * height); //int nZero = 4*nAlignWidth - 3*width; //for(int j=0; j<height; j++) //{ // for(int i=0; i<width*3; i++) // { // pDataAfterAlign[j*(nZero+3*width)+i] = pdata[3*width*j+i]; // } //} BITMAPFILEHEADER Header; BITMAPINFOHEADER HeaderInfo; Header.bfType = 0x4D42; Header.bfReserved1 = 0; Header.bfReserved2 = 0; Header.bfOffBits = (DWORD)( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); Header.bfSize = (DWORD)( sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nAlignWidth * height * 4); HeaderInfo.biSize = sizeof(BITMAPINFOHEADER); HeaderInfo.biWidth = width; HeaderInfo.biHeight = height; HeaderInfo.biPlanes = 1; HeaderInfo.biBitCount = 24; HeaderInfo.biCompression = 0; HeaderInfo.biSizeImage = 4 * nAlignWidth * height; HeaderInfo.biXPelsPerMeter = 0; HeaderInfo.biYPelsPerMeter = 0; HeaderInfo.biClrUsed = 0; HeaderInfo.biClrImportant = 0; FILE *pfile; if (!(pfile = fopen(lpFileName, "wb+"))) { printf("保存图像失败!\n"); return FALSE; } fwrite(&Header, 1, sizeof(BITMAPFILEHEADER), pfile); fwrite(&HeaderInfo, 1, sizeof(BITMAPINFOHEADER), pfile); fwrite(pdata, 1, HeaderInfo.biSizeImage, pfile); fclose(pfile); delete[] pdata; return TRUE; } void Keyboard(ESContext *esContext, unsigned char key, int winPosX, int winPosY) { //esLogMessage ( "Keyboard: %c, %d, %d", key, winPosX, winPosY ); if (key == ‘c‘ || key == ‘C‘) { esLogMessage ( "KeyPressed: %c\n", key); // TEST : copy from READ_BUFFER to texture //glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 10, 10, 15, 15, 100, 100); SaveBMP("screenshot.bmp"); } } 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 ); esRegisterKeyFunc( &esContext, Keyboard ); esMainLoop ( &esContext ); ShutDown ( &esContext ); }
《OpenGL ES 2.0 Programming Guide》第12章“最简单的ReadPixels并保存为BMP”示例代码【C语言版】
标签:test awt glin lte 语言 memset argv raw fbi
原文地址:http://blog.csdn.net/panda1234lee/article/details/52429200