OpenGL ES2.0編程三部曲(轉載自MyArrow)

1. 保存全局變量的數據結構

以下例子程序均基於Linux平臺。

  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.   
  11.    // Callbacks  
  12.    void (ESCALLBACK *drawFunc) ( struct _escontext * );  
  13.    void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned charintint );  
  14.    void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );  
  15. }ESContext;  
  1. typedef struct  
  2. {  
  3.    // Handle to a program object  
  4.    GLuint programObject;  
  5.   
  6.    // Atrribute Location  
  7.    GLint positionLoc;  
  8.    GLint textureLoc;  
  9.   
  10.    // Uniform location  
  11.    GLint matrixModeLoc;  
  12.    GLint matrixViewLoc;  
  13.    GLint matrixPerspectiveLoc;  
  14.   
  15.    // Sampler location  
  16.    GLint samplerLoc;  
  17.   
  18.    // texture  
  19.    GLuint texture;  
  20. } UserData;  



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

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


3. 生成Program (第二步曲)

3.1 LoadShader

LoadShader主要實現以下功能:

       1) 創建Shader對象

       2) 裝載Shader源碼

       3) 編譯Shader

      其實現參考代碼如下:

 

  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.   
  10.    if ( shader == 0 )  
  11.     return 0;  
  12.   
  13.    // Replaces the source code in a shader object  
  14.    glShaderSource ( shader, 1, &shaderSrc, NULL );  
  15.      
  16.    // Compile the shader object  
  17.    glCompileShader ( shader );  
  18.   
  19.    // Check the shader object compile status  
  20.    glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );  
  21.   
  22.    if ( !compiled )   
  23.    {  
  24.       GLint infoLen = 0;  
  25.   
  26.       glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );  
  27.         
  28.       if ( infoLen > 1 )  
  29.       {  
  30.          char* infoLog = malloc (sizeof(char) * infoLen );  
  31.   
  32.          glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );  
  33.          esLogMessage ( "Error compiling shader:\n%s\n", infoLog );              
  34.            
  35.          free ( infoLog );  
  36.       }  
  37.   
  38.       glDeleteShader ( shader );  
  39.       return 0;  
  40.    }  
  41.   
  42.    return shader;  
  43. }  

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

其參考代碼如下:

 

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

 

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的鏈接,現在還缺少真正供進行編譯和鏈接的源碼,其參考代碼如下:

 

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

4. 安裝並執行Program(第三步) 

  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.   
  14.    // Use the program object  
  15.    glUseProgram ( userData->programObject );  
  16.   
  17.    // Load the vertex data  
  18.    glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );  
  19.    glEnableVertexAttribArray ( 0 );  
  20.    glDrawArrays ( GL_TRIANGLES, 0, 3 );  
  21.    eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);  
  1. }  

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。

      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處開始的位置數據格式其定義如下:

 

  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.4 glEnableVertexAttribArray

      Enable由索引index指定的通用頂點屬性數組。

      void glEnableVertexAttribArray( GLuint   index);
      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

    只有這三個關鍵人物,還不能運行,還需要一個協調組織者。其參考代碼如下:   

  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.   
  9.     memset( &esContext, 0, sizeof( ESContext) );  
  10.     esContext.userData = &userData;  
  11.   
  12.     esContext.width = 1280;  
  13.     esContext.height = 720;  
  14.     // Init EGL display, surface and context  
  15.     if(!InitEGL(&esContext))  
  16.     {  
  17.         printf("Init EGL fail\n");  
  18.         return GL_FALSE;  
  19.     }  
  20.     // compile shader, link program   
  21.     if(!CreateProgram(&esContext))  
  22.     {  
  23.         printf("Create Program fail\n");  
  24.         return GL_FALSE;  
  25.     }  
  26.   
  27.   
  28.     iStartTime = GetCurTime();  
  29.     iFrames = 0;  
  30.   
  31.     while(1)  
  32.     {    // render a frame  
  33.          Render(&esContext);  
  34.          iFrames++;  
  35.           
  36.          iEndTime = GetCurTime();  
  37.     iDeltaTime  = iEndTime - iStartTime;  
  38.     if(iDeltaTime >= 5000)  
  39.     {  
  40.             iStartTime = iEndTime;  
  41.         float fFrame = iFrames * 1000.0 / iDeltaTime;  
  42.         iFrames = 0;  
  43.   
  44.         printf("Frame: %f\n", fFrame);  
  45.     }  
  46.     }  
  47.     glDeleteProgram (esContext.userData->programObject);  
  48.     return GL_TRUE;  
  49. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章