码迷,mamicode.com
首页 > 其他好文 > 详细

OpenGL ES 2.0 编程三步曲

时间:2015-03-20 10:56:23      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:opengl es

Android OpenGL库加载过程源码分析//http://mobile.51cto.com/aengine-437165.htm

本文简单介绍OpenGL库的加载过程。OpenGL以动态库的方式提供,因此在使用OpenGL的接口函数绘图前,需要加载OpenGL库,并得到接口函数指针。函数EGLBoolean egl_init_drivers()就是负责OpenGL库的加载。


很重要


///////////////////////////////////////////////////////////////

初始化EGL

OpenGL ES 是一个平台中立的图形库,在它能够工作之前,需要与一个实际的窗 口系统关联起来,这与 OpenGL 是一样的。但不一样的是,这部份工作有标准, 这个标准就是 EGL 。而 OpenGL 时代在不同平台上有不同的机制以关联窗口系 统,在 Windows 上是 wgl,在 X-Window 上是 xgl,在 Apple OS 上是 agl 等。 EGL 的工作方式和部份术语都接近于 xgl。

OpenGL ES的初始化过程如下图所示意:

Display → Config → Surface
                        ↑
                      Context
                        ↑
Application → OpenGL Command

1. 获取 Display。

Display 代表显示器,在有些系统上可以有多个显示器,也就会有多个 Display。 获得 Display 要调用

EGLboolean eglGetDisplay(NativeDisplay dpy)

参数一般为 EGL_DEFAULT_DISPLAY 。该参数实际的意义是平台实现相关的,在 X-Window 下是 XDisplay ID,在 MS Windows 下是 Window DC。

2. 初始化 egl。

初始化 egl 调用

EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)

该函数会进行一些内部初始化工作,并传回 EGL 版本号(major.minor)。

3. 选择Config。

所谓 Config 实际指的是 FrameBuffer 的参数,在 MS Windows 下对应于 PixelFormat,在 X-Window 下对应 Visual。一般用

EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list,
            EGLConfig * config, EGLint config_size, EGLint *num_config)

其中 attr_list 是以 EGL_NONE 结束的参数数组,通常以 id,value 依次存放, 对于个别标识性的属性可以只有 id,没有 value。

另一个办法是用

EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint
config_size, EGLint *num_config)

来获得所有 config。

这两个函数都会返回不多于 config_size 个 Config,结果保存在 config[] 中, 系统的总 Config 个数保存在 num_config 中。可以利用 eglGetConfig() 中间 两个参数为 0 来查询系统支持的 Config 总个数。

Config 有众多的 Attribute,这些 Attribute 决定 FrameBuffer 的格式和能 力,通过

eglGetConfigAttrib ()

来读取,但不能修改。

4. 构造Surface。

Surface 实际上就是一个 FrameBuffer,通过

EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg,
                NativeWindow win, EGLint *cfg_attr)

来创建一个可实际显示的 Surface。系统通常还支持另外两种 Surface: PixmapSurface 和 PBufferSurface,这两种都不是可显示的 Surface, PixmapSurface 是保存在系统内存中的位图,PBuffer 则是保存在显存中的帧。

Surface 也有一些 attribute,基本上都可以故名思意,

EGL_HEIGHT
EGL_WIDTH
EGL_LARGEST_PBUFFER
EGL_TEXTURE_FORMAT
EGL_TEXTURE_TARGET
EGL_MIPMAP_TEXTURE
EGL_MIPMAP_LEVEL

通过 eglSurfaceAttrib() 设置、eglQuerySurface()读取。

eglSurfaceAttrib()

eglQuerySurface()

5. 创建Context。

OpenGL 的 pipeline 从程序的角度看就是一个状态机,有当前的颜色、纹理坐 标、变换矩阵、绚染模式等一大堆状态,这些状态作用于程序提交的顶点坐标等 图元从而形成帧缓冲内的像素。

在 OpenGL 的编程接口中,Context 就代表这个状态机,程序的主要工作就是向 Context 提供图元、设置状态,偶尔也从 Context 里获取一些信息。

EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write,
                EGLSurface read, EGLContext * share_list)

来创建一个 Context。

6. 绘制。

应用程序通过 OpenGL API 进行绘制,一帧完成之后,调用

eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)

来显示。


OpenGL ES 2.0 编程三步曲


OpenGL 与 OpenGL ES的关系OpenGL ES 是基于桌面版本OpenGL 的:

OpenGL ES 1.0  基于OpenGL 1.3 , 在2003年发布

OpenGL ES 1.1   基于OpenGL 1.5 ,  在2004年发布

OpenGL ES 2.0  基于OpenGL2.0,   在2007年发布

OpenGL 2.0 向下兼容OpenGL 1.5   而 OpenGL ES 2.0 和OpenGL ES 1.x 不兼容,是两种完全不同的实现。

1. 保存全局变量的数据结构

以下例子程序均基于Linux平台。

[cpp]view plaincopy

  1. typedef struct _escontext   
  2. {   
  3.    void*       userData;                    // Put your user data here...   
  4.    GLint       width;                          // Window width   
  5.    GLint       height;                         // Window height   
  6.    EGLNativeWindowType  hWnd;  // Window handle   
  7.    EGLDisplay  eglDisplay;             // EGL display   
  8.    EGLContext  eglContext;            // EGL context   
  9.    EGLSurface  eglSurface;            // EGL surface   
  10.    // Callbacks   
  11.    void (ESCALLBACK *drawFunc) ( struct _escontext * );   
  12.    void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned charintint );   
  13.    void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );   
  14. }ESContext;   

[cpp]view plaincopy

  1. typedef struct   
  2. {   
  3.    // Handle to a program object   
  4.    GLuint programObject;   
  5.    // Atrribute Location   
  6.    GLint positionLoc;   
  7.    GLint textureLoc;   
  8.    // Uniform location   
  9.    GLint matrixModeLoc;   
  10.    GLint matrixViewLoc;   
  11.    GLint matrixPerspectiveLoc;   
  12.    // Sampler location   
  13.    GLint samplerLoc;   
  14.    // texture   
  15.    GLuint texture;   
  16. } UserData;  

2. 初始化EGL渲染环境和相关元素(第一步曲)

[cpp]view plaincopy

  1. int InitEGL(ESContext * esContext)   
  2. {   
  3.      NativeWindowType eglWindow = NULL;   
  4.      EGLDisplay display;   
  5.      EGLContext context;   
  6.      EGLSurface surface;   
  7.      EGLConfig configs[2];   
  8.      EGLBoolean eRetStatus;   
  9.      EGLint majorVer, minorVer;   
  10.      EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};   
  11.      EGLint numConfigs;   
  12.      EGLint cfg_attribs[] = {EGL_BUFFER_SIZE,    EGL_DONT_CARE,   
  13.                              EGL_DEPTH_SIZE,     16,   
  14.                              EGL_RED_SIZE,       5,   
  15.                              EGL_GREEN_SIZE,     6,   
  16.                              EGL_BLUE_SIZE,      5,   
  17.                              EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,   
  18.                              EGL_NONE};   
  19.      // Get default display connection    
  20.      display = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);   
  21.      if ( display == EGL_NO_DISPLAY )   
  22.      {   
  23.           return EGL_FALSE;   
  24.      }   
  25.      // Initialize EGL display connection   
  26.      eRetStatus = eglInitialize(display, &majorVer, &minorVer);   
  27.      if( eRetStatus != EGL_TRUE )   
  28.      {   
  29.           return EGL_FALSE;   
  30.      }   
  31.      //Get a list of all EGL frame buffer configurations for a display   
  32.      eRetStatus = eglGetConfigs (display, configs, 2, &numConfigs);   
  33.      if( eRetStatus != EGL_TRUE )   
  34.      {   
  35.           return EGL_FALSE;   
  36.      }   
  37.      // Get a list of EGL frame buffer configurations that match specified attributes   
  38.      eRetStatus = eglChooseConfig (display, cfg_attribs, configs, 2, &numConfigs);   
  39.      if( eRetStatus != EGL_TRUE  || !numConfigs)   
  40.      {   
  41.           return EGL_FALSE;   
  42.      }   
  43.      // Create a new EGL window surface   
  44.      surface = eglCreateWindowSurface(display, configs[0], eglWindow, NULL);   
  45.      if (surface == EGL_NO_SURFACE)   
  46.      {   
  47.           return EGL_FALSE;   
  48.      }   
  49.      // Set the current rendering API (EGL_OPENGL_API, EGL_OPENGL_ES_API,EGL_OPENVG_API)   
  50.      eRetStatus = eglBindAPI(EGL_OPENGL_ES_API);   
  51.      if (eRetStatus != EGL_TRUE)   
  52.      {   
  53.           return EGL_FALSE;   
  54.      }   
  55.      // Create a new EGL rendering context   
  56.      context = eglCreateContext (display, configs[0], EGL_NO_CONTEXT, context_attribs);   
  57.      if (context == EGL_NO_CONTEXT)   
  58.      {   
  59.           return EGL_FALSE;   
  60.      }   
  61.      // Attach an EGL rendering context to EGL surfaces   
  62.      eRetStatus = eglMakeCurrent (display, surface, surface, context);   
  63.      if( eRetStatus != EGL_TRUE )   
  64.      {   
  65.           return EGL_FALSE;   
  66.      }   
  67.      //If interval is set to a value of 0, buffer swaps are not synchronized to a video frame, and the swap happens as soon as the render is complete.   
  68.      eglSwapInterval(display,0);   
  69.      // Return the context elements   
  70.      esContext->eglDisplay = display;   
  71.      esContext->eglSurface = surface;   
  72.      esContext->eglContext = context;   
  73.      return EGL_TRUE;   
  74. }  

3. 生成Program (第二步曲)

3.1 LoadShader

LoadShader主要实现以下功能:

1) 创建Shader对象

2) 装载Shader源码

3) 编译Shader

其实现参考代码如下:

[cpp]view plaincopy

  1. /* type specifies the Shader type: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER */   
  2. GLuint LoadShader ( GLenum type, const char *shaderSrc )   
  3. {   
  4.    GLuint shader;   
  5.    GLint compiled;   
  6.       
  7.    // Create an empty shader object, which maintain the source code strings that define a shader   
  8.    shader = glCreateShader ( type );   
  9.    if ( shader == 0 )   
  10.     return 0;   
  11.    // Replaces the source code in a shader object   
  12.    glShaderSource ( shader, 1, &shaderSrc, NULL );   
  13.       
  14.    // Compile the shader object   
  15.    glCompileShader ( shader );   
  16.    // Check the shader object compile status   
  17.    glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );   
  18.    if ( !compiled )    
  19.    {   
  20.       GLint infoLen = 0;   
  21.       glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );   
  22.          
  23.       if ( infoLen > 1 )   
  24.       {   
  25.          char* infoLog = malloc (sizeof(char) * infoLen );   
  26.          glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );   
  27.          esLogMessage ( "Error compiling shader:\n%s\n", infoLog );               
  28.             
  29.          free ( infoLog );   
  30.       }   
  31.       glDeleteShader ( shader );   
  32.       return 0;   
  33.    }   
  34.    return shader;   
  35. }   

1)glCreateShader

它创建一个空的shader对象,它用于维护用来定义shader的源码字符串。支持以下两种shader:

(1) GL_VERTEX_SHADER: 它运行在可编程的“顶点处理器”上,用于代替固定功能的顶点处理;

(2) GL_FRAGMENT_SHADER: 它运行在可编程的“片断处理器”上,用于代替固定功能的片段处理;

2)glShaderSource

shader对象中原来的源码全部被新的源码所代替。

3)glCompileShader

编译存储在shader对象中的源码字符串,编译结果被当作shader对象状态的一部分被保存起来,可通过glGetShaderiv函数获取编译状态。

4)glGetShaderiv

获取shader对象参数,参数包括:GL_SHADER_TYPE, GL_DELETE_STATUS, GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH.

3.2 LoadProgram

其参考代码如下:

[cpp]view plaincopy

  1. GLuint LoadProgram ( const char *vShaderStr, const char *fShaderStr )   
  2. {   
  3.    GLuint vertexShader;   
  4.    GLuint fragmentShader;   
  5.    GLuint programObject;   
  6.    GLint linked;   
  7.    // Load the vertex/fragment shaders   
  8.    vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );   
  9.    fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );   
  10.    // Create the program object   
  11.    programObject = glCreateProgram ( );   
  12.    if ( programObject == 0 )   
  13.       return 0;   
  14.    // Attaches a shader object to a program object   
  15.    glAttachShader ( programObject, vertexShader );   
  16.    glAttachShader ( programObject, fragmentShader );   
  17.    // Bind vPosition to attribute 0      
  18.    glBindAttribLocation ( programObject, 0, "vPosition" );   
  19.    // Link the program object   
  20.    glLinkProgram ( programObject );   
  21.    // Check the link status   
  22.    glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );   
  23.    if ( !linked )    
  24.    {   
  25.       GLint infoLen = 0;   
  26.       glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );   
  27.          
  28.       if ( infoLen > 1 )   
  29.       {   
  30.          char* infoLog = malloc (sizeof(char) * infoLen );   
  31.          glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );   
  32.          esLogMessage ( "Error linking program:\n%s\n", infoLog );               
  33.             
  34.          free ( infoLog );   
  35.       }   
  36.       glDeleteProgram ( programObject );   
  37.       return GL_FALSE;   
  38.    }   
  39.     
  40.    // Free no longer needed shader resources   
  41.    glDeleteShader ( vertexShader );   
  42.    glDeleteShader ( fragmentShader );   
  43.    return programObject;   
  44. }   

1)glCreateProgram

建立一个空的program对象,shader对象可以被连接到program对像

2)glAttachShader

program对象提供了把需要做的事连接在一起的机制。在一个program中,在shader对象被连接在一起之前,必须先把shader连接到program上。

3)glBindAttribLocation

把program的顶点属性索引与顶点shader中的变量名进行绑定。

4)glLinkProgram

连接程序对象。如果任何类型为GL_VERTEX_SHADER的shader对象连接到program,它将产生在“可编程顶点处理器”上可执行的程 序;如果任何类型为GL_FRAGMENT_SHADER的shader对象连接到program,它将产生在“可编程片断处理器”上可执行的程序。

5)glGetProgramiv

获取program对象的参数值,参数有:GL_DELETE_STATUS, GL_LINK_STATUS, GL_VALIDATE_STATUS, GL_INFO_LOG_LENGTH, GL_ATTACHED_SHADERS, GL_ACTIVE_ATTRIBUTES, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, GL_ACTIVE_UNIFORMS, GL_ACTIVE_UNIFORM_MAX_LENGTH.

3.3 CreateProgram

在3.1中只实现了Shader的编译,在3.2中只实现了Program的链接,现在还缺少真正供进行编译和链接的源码,其参考代码如下:

[cpp]view plaincopy

  1. int CreateProgram(ESContext * esContext)   
  2. {   
  3.      GLuint programObject;   
  4.      GLbyte vShaderStr[] =     
  5.       "attribute vec4 vPosition;    \n"   
  6.       "void main()                  \n"   
  7.       "{                            \n"   
  8.       "   gl_Position = vPosition;  \n"   
  9.       "}                            \n";   
  10.       
  11.      GLbyte fShaderStr[] =     
  12.       "precision mediump float;\n"\   
  13.       "void main()                                  \n"   
  14.       "{                                            \n"   
  15.       "  gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"   
  16.       "}                                                    \n";   
  17.        
  18.     // Create user data    
  19.     esContext->userData = malloc(sizeof(UserData));   
  20.     UserData *userData = esContext->userData;   
  21.     // Load the shaders and get a linked program object   
  22.     programObject = LoadProgram ( (const char*)vShaderStr, (const char*)fShaderStr );   
  23.     if(programObject == 0)   
  24.     {   
  25.     return GL_FALSE;   
  26.     }   
  27.     // Store the program object   
  28.     userData->programObject = programObject;   
  29.     // Get the attribute locations   
  30.     userData->positionLoc = glGetAttribLocation ( g_programObject, "v_position" );   
  31.     glClearColor ( 0.0f, 0.0f, 0.0f, 1.0f );   
  32.     return 0;   
  33. }   

4. 安装并执行Program(第三步) 

[cpp]view plaincopy

  1. void Render ( ESContext *esContext )   
  2. {   
  3.    UserData *userData = esContext->userData;   
  4.    GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,    
  5.                            -0.5f, -0.5f, 0.0f,   
  6.                             0.5f, -0.5f, 0.0f };   
  7.          
  8.    // Set the viewport   
  9.    glViewport ( 0, 0, esContext->width, esContext->height );   
  10.       
  11.    // Clear the color buffer   
  12.    glClear ( GL_COLOR_BUFFER_BIT );   
  13.    // Use the program object   
  14.    glUseProgram ( userData->programObject );   
  15.    // Load the vertex data   
  16.    glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );   
  17.    glEnableVertexAttribArray ( 0 );   
  18.    glDrawArrays ( GL_TRIANGLES, 0, 3 );   
  19.    eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);

[cpp]view plaincopy

4.1 glClear

清除指定的buffer到预设值。可清除以下四类buffer:

1)GL_COLOR_BUFFER_BIT

2)GL_DEPTH_BUFFER_BIT

3)GL_ACCUM_BUFFER_BIT

4)GL_STENCIL_BUFFER_BIT

预设值通过glClearColor, glClearIndex, glClearDepth, glClearStencil, 和glClearAccum来设置。

1)gClearColor

指定color buffer的清除值,当调用glClear(GL_COLOR_BUFFER_BIT)时才真正用设定的颜色值清除color buffer。参数值的范围为:0~1。

  1. void glClearColor( GLclampf   red, GLclampf   green,  GLclampf   blue,  GLclampf   alpha); 

2)glClearIndex

指定color index buffer清除值。void glClearIndex( GLfloat   c);

3)glClearDepth

   指定depth buffer的清除值,取值范围为:0~1,默认值为1。

void glClearDepth( GLclampd   depth);

4)glClearStencil

 指定stencil buffer清除值的索引,初始值为0。void glClearStencil( GLint   s);

5)glClearAccum

指定accumulation buffer的清除值,初始值为0,取值范围为:-1~1

void glClearAccum( GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha);

4.2 glUseProgram

安装一个program object,并把它作为当前rendering state的一部分。

1) 当一个可执行程序被安装到vertex processor,下列OpenGL固定功能将被disable:

  • The modelview matrix is not applied to vertex coordinates.
  • The projection matrix is not applied to vertex coordinates.
  • The texture matrices are not applied to texture coordinates.
  • Normals are not transformed to eye coordinates.
  • Normals are not rescaled or normalized.
  • Normalization of GL_AUTO_NORMAL evaluated normals is not performed.
  • Texture coordinates are not generated automatically.
  • Per-vertex lighting is not performed.
  • Color material computations are not performed.
  • Color index lighting is not performed.
  • This list also applies when setting the current raster position.

2)当一个可执行程序被安装到fragment processor,下列OpenGL固定功能将被disable:

  • Texture environment and texture functions are not applied.
  • Texture application is not applied.
  • Color sum is not applied.
  • Fog is not applied.

4.3 glVertexAttribPointer

定义一个通用顶点属性数组。当渲染时,它指定了通用顶点属性数组从索引index处开始的位置和数据格式。其定义如下:

[cpp]view plaincopy

  1. void glVertexAttribPointer(   
  2.       GLuint   index,           // 指示将被修改的通用顶点属性的索引   
  3.        GLint   size,             // 指点每个顶点元素个数(1~4)   
  4.       GLenum   type,            // 数组中每个元素的数据类型   
  5.        GLboolean   normalized,   //指示定点数据值是否被归一化(归一化<[-1,1]或[0,1]>:GL_TRUE,直接使用:GL_FALSE)   
  6.       GLsizei   stride,         // 连续顶点属性间的偏移量,如果为0,相邻顶点属性间紧紧相邻   
  7.        const GLvoid *   pointer);//顶点数组   
  8. :其index应该小于#define GL_MAX_VERTEX_ATTRIBS               0x8869   

4.4glEnableVertexAttribArray

Enable由索引index指定的通用顶点属性数组。

  1. void glEnableVertexAttribArray( GLuint   index); 
  2. void glDisableVertexAttribArray( GLuint   index);

默认状态下,所有客户端的能力被disabled,包括所有通用顶点属性数组。如果被Enable,通用顶点属性数组中的值将被访问并被用于rendering,通过调用顶点数组命令:glDrawArrays, glDrawElements, glDrawRangeElements, glArrayElement, glMultiDrawElements, or glMultiDrawArrays.

4.5 glDrawArrays

void glDrawArrays( GLenum   mode, 

    GLint   first, 

 GLsizei   count);

1) mode:指明render原语,如:GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, 和 GL_POLYGON。

2) first: 指明Enable数组中起始索引。

3) count: 指明被render的原语个数。

可以预先使用单独的数据定义vertex、normal和color,然后通过一个简单的glDrawArrays构造一系列原语。当调用 glDrawArrays时,它使用每个enable的数组中的count个连续的元素,来构造一系列几何原语,从第first个元素开始。

4.6 eglSwapBuffers

把EGL surface中的color buffer提交到native window进行显示。 

EGLBoolean eglSwapBuffers(EGLDisplay display,EGLSurface surface)

5. 协调组织

在前面的描述中,三步曲已经完成了:

1)初始化EGL环境,为绘图做好准备

2)生成Program

3)安装并执行Program

只有这三个关键人物,还不能运行,还需要一个协调组织者。其参考代码如下:   

[cpp]view plaincopy

  1. int main(int argc, char** argv)   
  2. {   
  3.     ESContext esContext;   
  4.     UserData  userData;   
  5.     int iFrames;    
  6.     unsigned long iStartTime,iEndTime;   
  7.     int iDeltaTime;   
  8.     memset( &esContext, 0, sizeof( ESContext) );   
  9.     esContext.userData = &userData;   
  10.     esContext.width = 1280;   
  11.     esContext.height = 720;   
  12.     // Init EGL display, surface and context   
  13.     if(!InitEGL(&esContext))   
  14.     {   
  15.         printf("Init EGL fail\n");   
  16.         return GL_FALSE;   
  17.     }   
  18.     // compile shader, link program    
  19.     if(!CreateProgram(&esContext))   
  20.     {   
  21.         printf("Create Program fail\n");   
  22.         return GL_FALSE;   
  23.     }   
  24.     iStartTime = GetCurTime();   
  25.     iFrames = 0;   
  26.     while(1)   
  27.     {    // render a frame   
  28.          Render();   
  29.          iFrames++;   
  30.            
  31.          iEndTime = GetCurTime();   
  32.     iDeltaTime  = iEndTime - iStartTime;   
  33.     if(iDeltaTime >= 5000)   
  34.     {   
  35.             iStartTime = iEndTime;   
  36.         float fFrame = iFrames * 1000.0 / iDeltaTime;   
  37.         iFrames = 0;   
  38.         printf("Frame.: %f\n", fFrame);   
  39.     }   
  40.     }   
  41.     glDeleteProgram (esContext.userData->programObject);   
  42.     return GL_TRUE;   
  43. }  

//http://mobile.51cto.com/app-show-436809.htm



OpenGL ES 2.0 编程三步曲

标签:opengl es

原文地址:http://blog.csdn.net/u013467442/article/details/44487997

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!