Since the original book of the OpenGL ES 2.0 Programming Guide does not provide the sample code for the 12th chapter, the code in the book only mentions the key steps, and most of the Web is an example of the Android/ios version, most of which are based on OpenGL or OpenGL ES 3.0, in order to deepen understanding, so that their own implementation of a C language version, hoping to help the same like OpenGL ES 2.0 classmates.
Nonsense not much to say directly on the code
#include "stdafx.h" #include "esUtil.h" #include <stdlib.h> #include <stdio.h> #define SIZE 512typedef 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//t He 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_REN Derbuffer, 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 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, 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 (&us Erdata->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 (u Serdata->positionfboloc, 3, Gl_float, Gl_false, 3 * sizeof (glfloat), userdata->vertices) ; Glenablevertexattribarray (Userdata->positionfboloc); -----------------------------------------------------------//Load the texture coordinate//glvertexattribpointe R (Userdata->texcoordloc, 2, Gl_float,//gl_false, 2 * sizeof (glfloat), userdata->texcoords); Glenablevertexattribarray (Userdata->teXCOORDLOC); -----------------------------------------------------------//Load the MVP matrix GLUNIFORMMATRIX4FV (userdata-& Gt;mvpfboloc, 1, Gl_false, (Glfloat *) &userdata->mvpmatrix.m[0][0]); -----------------------------------------------------------//Draw the cube gldrawelements (Gl_triangles, UserD Ata->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-& Gt;mvploc, 1, Gl_false, (Glfloat *) &userdata->mvpmatrix.m[0][0]); -----------------------------------------------------------//Bind the texture//Set The sampler texture Unit T o 0 glactivetexture (GL_TEXTURE0); Glbindtexture (gl_texture_2d, userdata->texture); Glgeneratemipmap (gl_texture_2d); Gluniform1i (Userdata->samplerloc,0); -----------------------------------------------------------//Draw the cube gldrawelements (Gl_triangles, UserD Ata->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);//read Pixels glreadpixels from the currently bound frame buffer (0, 0, width, height, gl_rgb, G L_unsigned_byte, pdata); Changed from RGB to 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; }////four-byte alignment//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
Press C or C to screenshot, save picture as Screenshot.bmp
OpenGL ES 2.0 Programming Guide Chapter 12th "simplest Readpixels and Save as BMP" sample code "C Language"