NDK的OpenGLes2.0 官方例子解析

发表于2017-09-14
评论0 2.8k浏览

提要

NDK自带了一个OpenGLes的例子,下面就一起来学习一下。

环境:Ubuntu14.04 NDK r10 ADT13.02 Android Native Development Tools 8.12

注:在ubuntu的adt需要手动安装Android Native Development Tools才能很好的支持NDK。

如果你对Java调用C/C 的代码还不了解,可以参考:JNI原理及实现  利用JNI进行对象操作

如果你对NDK还不了解,可以参考:Android的NDK开发(1)-不一样的HelloWorld

如果你对NDK下的OpenGL es 编程不了解,可以参考:Android的NDK开发(2)-基于NDK的OpenGL开发


加载项目

File -> Import -> Existing Android Code Into Workspace 

定位到ndk的目录,samples -> hello-gl2,加载就可以了。加载好之后目录的结构是像这样的:



Java的代码主要aom.android.gl2jni目录下面,C 的代码主要就在jni目录,obj目录是ndk编译产生的一些文件,libs下面是ndk交叉编译出的各个版本cpu所使用的库版本。

运行结果非常简单,中间一个三角形,背景从白到黑不断变换。



代码分析

首先来看下java的代码

GL2JNILib.java

[java] view plain copy
  1. public class GL2JNILib {  
  2.   
  3.      static {  
  4.          System.loadLibrary("gl2jni");  
  5.      }  
  6.   
  7.     /** 
  8.      * @param width the current view width 
  9.      * @param height the current view height 
  10.      */  
  11.      public static native void init(int width, int height);  
  12.      public static native void step();  
  13. }  

这个类作为Java和C 的桥,用System.loadLibrary()方法来加载C 的库,接着声明一些C 实现好的一些静态公有方法。算是一种小小的封装吧。


GL2JNIView.java

[java] view plain copy
  1. class GL2JNIView extends GLSurfaceView {  
  2.     private static String TAG = "GL2JNIView";  
  3.     private static final boolean DEBUG = false;  
  4.   
  5.     public GL2JNIView(Context context) {  
  6.         super(context);  
  7.         init(false00);  
  8.     }  
  9.   
  10.     public GL2JNIView(Context context, boolean translucent, int depth, int stencil) {  
  11.         super(context);  
  12.         init(translucent, depth, stencil);  
  13.     }  
  14.   
  15.     private void init(boolean translucent, int depth, int stencil) {  
  16.   
  17.         /* By default, GLSurfaceView() creates a RGB_565 opaque surface. 
  18.          * If we want a translucent one, we should change the surface's 
  19.          * format here, using PixelFormat.TRANSLUCENT for GL Surfaces 
  20.          * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. 
  21.          */  
  22.         if (translucent) {  
  23.             this.getHolder().setFormat(PixelFormat.TRANSLUCENT);  
  24.         }  
  25.   
  26.         /* Setup the context factory for 2.0 rendering. 
  27.          * See ContextFactory class definition below 
  28.          */  
  29.         setEGLContextFactory(new ContextFactory());  
  30.   
  31.         /* We need to choose an EGLConfig that matches the format of 
  32.          * our surface exactly. This is going to be done in our 
  33.          * custom config chooser. See ConfigChooser class definition 
  34.          * below. 
  35.          */  
  36.         setEGLConfigChooser( translucent ?  
  37.                              new ConfigChooser(8888, depth, stencil) :  
  38.                              new ConfigChooser(5650, depth, stencil) );  
  39.   
  40.         /* Set the renderer responsible for frame rendering */  
  41.         setRenderer(new Renderer());  
  42.     }  
  43.   
  44.     private static class ContextFactory implements GLSurfaceView.EGLContextFactory {  
  45.         private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;  
  46.         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {  
  47.             Log.w(TAG, "creating OpenGL ES 2.0 context");  
  48.             checkEglError("Before eglCreateContext", egl);  
  49.             int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };  
  50.             EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);  
  51.             checkEglError("After eglCreateContext", egl);  
  52.             return context;  
  53.         }  
  54.   
  55.         public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {  
  56.             egl.eglDestroyContext(display, context);  
  57.         }  
  58.     }  
  59.   
  60.     private static void checkEglError(String prompt, EGL10 egl) {  
  61.         int error;  
  62.         while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {  
  63.             Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));  
  64.         }  
  65.     }  
  66.   
  67.     private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {  
  68.   
  69.         public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {  
  70.             mRedSize = r;  
  71.             mGreenSize = g;  
  72.             mBlueSize = b;  
  73.             mAlphaSize = a;  
  74.             mDepthSize = depth;  
  75.             mStencilSize = stencil;  
  76.         }  
  77.   
  78.         /* This EGL config specification is used to specify 2.0 rendering. 
  79.          * We use a minimum size of 4 bits for red/green/blue, but will 
  80.          * perform actual matching in chooseConfig() below. 
  81.          */  
  82.         private static int EGL_OPENGL_ES2_BIT = 4;  
  83.         private static int[] s_configAttribs2 =  
  84.         {  
  85.             EGL10.EGL_RED_SIZE, 4,  
  86.             EGL10.EGL_GREEN_SIZE, 4,  
  87.             EGL10.EGL_BLUE_SIZE, 4,  
  88.             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,  
  89.             EGL10.EGL_NONE  
  90.         };  
  91.   
  92.         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {  
  93.   
  94.             /* Get the number of minimally matching EGL configurations 
  95.              */  
  96.             int[] num_config = new int[1];  
  97.             egl.eglChooseConfig(display, s_configAttribs2, null0, num_config);  
  98.   
  99.             int numConfigs = num_config[0];  
  100.   
  101.             if (numConfigs <= 0) {  
  102.                 throw new IllegalArgumentException("No configs match configSpec");  
  103.             }  
  104.   
  105.             /* Allocate then read the array of minimally matching EGL configs 
  106.              */  
  107.             EGLConfig[] configs = new EGLConfig[numConfigs];  
  108.             egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);  
  109.   
  110.             if (DEBUG) {  
  111.                  printConfigs(egl, display, configs);  
  112.             }  
  113.             /* Now return the "best" one 
  114.              */  
  115.             return chooseConfig(egl, display, configs);  
  116.         }  
  117.   
  118.         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,  
  119.                 EGLConfig[] configs) {  
  120.             for(EGLConfig config : configs) {  
  121.                 int d = findConfigAttrib(egl, display, config,  
  122.                         EGL10.EGL_DEPTH_SIZE, 0);  
  123.                 int s = findConfigAttrib(egl, display, config,  
  124.                         EGL10.EGL_STENCIL_SIZE, 0);  
  125.   
  126.                 // We need at least mDepthSize and mStencilSize bits  
  127.                 if (d < mDepthSize || s < mStencilSize)  
  128.                     continue;  
  129.   
  130.                 // We want an *exact* match for red/green/blue/alpha  
  131.                 int r = findConfigAttrib(egl, display, config,  
  132.                         EGL10.EGL_RED_SIZE, 0);  
  133.                 int g = findConfigAttrib(egl, display, config,  
  134.                             EGL10.EGL_GREEN_SIZE, 0);  
  135.                 int b = findConfigAttrib(egl, display, config,  
  136.                             EGL10.EGL_BLUE_SIZE, 0);  
  137.                 int a = findConfigAttrib(egl, display, config,  
  138.                         EGL10.EGL_ALPHA_SIZE, 0);  
  139.   
  140.                 if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)  
  141.                     return config;  
  142.             }  
  143.             return null;  
  144.         }  
  145.   
  146.         private int findConfigAttrib(EGL10 egl, EGLDisplay display,  
  147.                 EGLConfig config, int attribute, int defaultValue) {  
  148.   
  149.             if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {  
  150.                 return mValue[0];  
  151.             }  
  152.             return defaultValue;  
  153.         }  
  154.   
  155.         private void printConfigs(EGL10 egl, EGLDisplay display,  
  156.             EGLConfig[] configs) {  
  157.             int numConfigs = configs.length;  
  158.             Log.w(TAG, String.format("%d configurations", numConfigs));  
  159.             for (int i = 0; i < numConfigs; i ) {  
  160.                 Log.w(TAG, String.format("Configuration %d:\n", i));  
  161.                 printConfig(egl, display, configs[i]);  
  162.             }  
  163.         }  
  164.   
  165.         private void printConfig(EGL10 egl, EGLDisplay display,  
  166.                 EGLConfig config) {  
  167.             int[] attributes = {  
  168.                     EGL10.EGL_BUFFER_SIZE,  
  169.                     EGL10.EGL_ALPHA_SIZE,  
  170.                     EGL10.EGL_BLUE_SIZE,  
  171.                     EGL10.EGL_GREEN_SIZE,  
  172.                     EGL10.EGL_RED_SIZE,  
  173.                     EGL10.EGL_DEPTH_SIZE,  
  174.                     EGL10.EGL_STENCIL_SIZE,  
  175.                     EGL10.EGL_CONFIG_CAVEAT,  
  176.                     EGL10.EGL_CONFIG_ID,  
  177.                     EGL10.EGL_LEVEL,  
  178.                     EGL10.EGL_MAX_PBUFFER_HEIGHT,  
  179.                     EGL10.EGL_MAX_PBUFFER_PIXELS,  
  180.                     EGL10.EGL_MAX_PBUFFER_WIDTH,  
  181.                     EGL10.EGL_NATIVE_RENDERABLE,  
  182.                     EGL10.EGL_NATIVE_VISUAL_ID,  
  183.                     EGL10.EGL_NATIVE_VISUAL_TYPE,  
  184.                     0x3030// EGL10.EGL_PRESERVED_RESOURCES,  
  185.                     EGL10.EGL_SAMPLES,  
  186.                     EGL10.EGL_SAMPLE_BUFFERS,  
  187.                     EGL10.EGL_SURFACE_TYPE,  
  188.                     EGL10.EGL_TRANSPARENT_TYPE,  
  189.                     EGL10.EGL_TRANSPARENT_RED_VALUE,  
  190.                     EGL10.EGL_TRANSPARENT_GREEN_VALUE,  
  191.                     EGL10.EGL_TRANSPARENT_BLUE_VALUE,  
  192.                     0x3039// EGL10.EGL_BIND_TO_TEXTURE_RGB,  
  193.                     0x303A// EGL10.EGL_BIND_TO_TEXTURE_RGBA,  
  194.                     0x303B// EGL10.EGL_MIN_SWAP_INTERVAL,  
  195.                     0x303C// EGL10.EGL_MAX_SWAP_INTERVAL,  
  196.                     EGL10.EGL_LUMINANCE_SIZE,  
  197.                     EGL10.EGL_ALPHA_MASK_SIZE,  
  198.                     EGL10.EGL_COLOR_BUFFER_TYPE,  
  199.                     EGL10.EGL_RENDERABLE_TYPE,  
  200.                     0x3042 // EGL10.EGL_CONFORMANT  
  201.             };  
  202.             String[] names = {  
  203.                     "EGL_BUFFER_SIZE",  
  204.                     "EGL_ALPHA_SIZE",  
  205.                     "EGL_BLUE_SIZE",  
  206.                     "EGL_GREEN_SIZE",  
  207.                     "EGL_RED_SIZE",  
  208.                     "EGL_DEPTH_SIZE",  
  209.                     "EGL_STENCIL_SIZE",  
  210.                     "EGL_CONFIG_CAVEAT",  
  211.                     "EGL_CONFIG_ID",  
  212.                     "EGL_LEVEL",  
  213.                     "EGL_MAX_PBUFFER_HEIGHT",  
  214.                     "EGL_MAX_PBUFFER_PIXELS",  
  215.                     "EGL_MAX_PBUFFER_WIDTH",  
  216.                     "EGL_NATIVE_RENDERABLE",  
  217.                     "EGL_NATIVE_VISUAL_ID",  
  218.                     "EGL_NATIVE_VISUAL_TYPE",  
  219.                     "EGL_PRESERVED_RESOURCES",  
  220.                     "EGL_SAMPLES",  
  221.                     "EGL_SAMPLE_BUFFERS",  
  222.                     "EGL_SURFACE_TYPE",  
  223.                     "EGL_TRANSPARENT_TYPE",  
  224.                     "EGL_TRANSPARENT_RED_VALUE",  
  225.                     "EGL_TRANSPARENT_GREEN_VALUE",  
  226.                     "EGL_TRANSPARENT_BLUE_VALUE",  
  227.                     "EGL_BIND_TO_TEXTURE_RGB",  
  228.                     "EGL_BIND_TO_TEXTURE_RGBA",  
  229.                     "EGL_MIN_SWAP_INTERVAL",  
  230.                     "EGL_MAX_SWAP_INTERVAL",  
  231.                     "EGL_LUMINANCE_SIZE",  
  232.                     "EGL_ALPHA_MASK_SIZE",  
  233.                     "EGL_COLOR_BUFFER_TYPE",  
  234.                     "EGL_RENDERABLE_TYPE",  
  235.                     "EGL_CONFORMANT"  
  236.             };  
  237.             int[] value = new int[1];  
  238.             for (int i = 0; i < attributes.length; i ) {  
  239.                 int attribute = attributes[i];  
  240.                 String name = names[i];  
  241.                 if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {  
  242.                     Log.w(TAG, String.format("  %s: %d\n", name, value[0]));  
  243.                 } else {  
  244.                     // Log.w(TAG, String.format("  %s: failed\n", name));  
  245.                     while (egl.eglGetError() != EGL10.EGL_SUCCESS);  
  246.                 }  
  247.             }  
  248.         }  
  249.   
  250.         // Subclasses can adjust these values:  
  251.         protected int mRedSize;  
  252.         protected int mGreenSize;  
  253.         protected int mBlueSize;  
  254.         protected int mAlphaSize;  
  255.         protected int mDepthSize;  
  256.         protected int mStencilSize;  
  257.         private int[] mValue = new int[1];  
  258.     }  
  259.   
  260.     private static class Renderer implements GLSurfaceView.Renderer {  
  261.         public void onDrawFrame(GL10 gl) {  
  262.             GL2JNILib.step();  
  263.         }  
  264.   
  265.         public void onSurfaceChanged(GL10 gl, int width, int height) {  
  266.             GL2JNILib.init(width, height);  
  267.         }  
  268.   
  269.         public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  270.             // Do nothing.  
  271.         }  
  272.     }  
  273. }  

这个类自定义了一个SurfaceView,作为Activity的content,定义了一个Renderer用于渲染内容,分别实现了Render的onDrawFrame和onSurfaceChanged方法,这里就直接调用GL2JNILib的静态共有方法了。


还定义了两个类,一个ContextFactory,用与生成OpenGL的Context。

一个ConfigChooser,用于选定支持es 2.0 的EGLConfig。

感觉这几个类分开写一下会更清晰一些。


GL2JNIActivity.java

[java] view plain copy
  1. public class GL2JNIActivity extends Activity {  
  2.   
  3.     GL2JNIView mView;  
  4.   
  5.     @Override protected void onCreate(Bundle icicle) {  
  6.         super.onCreate(icicle);  
  7.         mView = new GL2JNIView(getApplication());  
  8.     setContentView(mView);  
  9.     }  
  10.   
  11.     @Override protected void onPause() {  
  12.         super.onPause();  
  13.         mView.onPause();  
  14.     }  
  15.   
  16.     @Override protected void onResume() {  
  17.         super.onResume();  
  18.         mView.onResume();  
  19.     }  
  20. }  


这个类的定义了主要的Activity,只是简单的new了一个刚才定义好的GL2JNIView,然后设为content。


JNI方面,主要看gl_code.cpp就好了。

  1. // OpenGL ES 2.0 code  
  2.   
  3. #include   
  4. #include   
  5.   
  6. #include   
  7. #include   
  8.   
  9. #include   
  10. #include   
  11. #include   
  12.   
  13. #define  LOG_TAG    "libgl2jni"  
  14. #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  15. #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  16.   
  17. static void printGLString(const char *name, GLenum s) {  
  18.     const char *v = (const char *) glGetString(s);  
  19.     LOGI("GL %s = %s\n", name, v);  
  20. }  
  21.   
  22. static void checkGlError(const char* op) {  
  23.     for (GLint error = glGetError(); error; error  
  24.             = glGetError()) {  
  25.         LOGI("after %s() glError (0x%x)\n", op, error);  
  26.     }  
  27. }  
  28.   
  29. static const char gVertexShader[] =   
  30.     "attribute vec4 vPosition;\n"  
  31.     "void main() {\n"  
  32.     "  gl_Position = vPosition;\n"  
  33.     "}\n";  
  34.   
  35. static const char gFragmentShader[] =   
  36.     "precision mediump float;\n"  
  37.     "void main() {\n"  
  38.     "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"  
  39.     "}\n";  
  40.   
  41. GLuint loadShader(GLenum shaderType, const char* pSource) {  
  42.     GLuint shader = glCreateShader(shaderType);  
  43.     if (shader) {  
  44.         glShaderSource(shader, 1, &pSource, NULL);  
  45.         glCompileShader(shader);  
  46.         GLint compiled = 0;  
  47.         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);  
  48.         if (!compiled) {  
  49.             GLint infoLen = 0;  
  50.             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);  
  51.             if (infoLen) {  
  52.                 char* buf = (char*) malloc(infoLen);  
  53.                 if (buf) {  
  54.                     glGetShaderInfoLog(shader, infoLen, NULL, buf);  
  55.                     LOGE("Could not compile shader %d:\n%s\n",  
  56.                             shaderType, buf);  
  57.                     free(buf);  
  58.                 }  
  59.                 glDeleteShader(shader);  
  60.                 shader = 0;  
  61.             }  
  62.         }  
  63.     }  
  64.     return shader;  
  65. }  
  66.   
  67. GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {  
  68.     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);  
  69.     if (!vertexShader) {  
  70.         return 0;  
  71.     }  
  72.   
  73.     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);  
  74.     if (!pixelShader) {  
  75.         return 0;  
  76.     }  
  77.   
  78.     GLuint program = glCreateProgram();  
  79.     if (program) {  
  80.         glAttachShader(program, vertexShader);  
  81.         checkGlError("glAttachShader");  
  82.         glAttachShader(program, pixelShader);  
  83.         checkGlError("glAttachShader");  
  84.         glLinkProgram(program);  
  85.         GLint linkStatus = GL_FALSE;  
  86.         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);  
  87.         if (linkStatus != GL_TRUE) {  
  88.             GLint bufLength = 0;  
  89.             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);  
  90.             if (bufLength) {  
  91.                 char* buf = (char*) malloc(bufLength);  
  92.                 if (buf) {  
  93.                     glGetProgramInfoLog(program, bufLength, NULL, buf);  
  94.                     LOGE("Could not link program:\n%s\n", buf);  
  95.                     free(buf);  
  96.                 }  
  97.             }  
  98.             glDeleteProgram(program);  
  99.             program = 0;  
  100.         }  
  101.     }  
  102.     return program;  
  103. }  
  104.   
  105. GLuint gProgram;  
  106. GLuint gvPositionHandle;  
  107.   
  108. bool setupGraphics(int w, int h) {  
  109.     printGLString("Version", GL_VERSION);  
  110.     printGLString("Vendor", GL_VENDOR);  
  111.     printGLString("Renderer", GL_RENDERER);  
  112.     printGLString("Extensions", GL_EXTENSIONS);  
  113.   
  114.     LOGI("setupGraphics(%d, %d)", w, h);  
  115.     gProgram = createProgram(gVertexShader, gFragmentShader);  
  116.     if (!gProgram) {  
  117.         LOGE("Could not create program.");  
  118.         return false;  
  119.     }  
  120.     gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");  
  121.     checkGlError("glGetAttribLocation");  
  122.     LOGI("glGetAttribLocation(\"vPosition\") = %d\n",  
  123.             gvPositionHandle);  
  124.   
  125.     glViewport(0, 0, w, h);  
  126.     checkGlError("glViewport");  
  127.     return true;  
  128. }  
  129.   
  130. const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,  
  131.         0.5f, -0.5f };  
  132.   
  133. void renderFrame() {  
  134.     static float grey;  
  135.     grey  = 0.01f;  
  136.     if (grey > 1.0f) {  
  137.         grey = 0.0f;  
  138.     }  
  139.     glClearColor(grey, grey, grey, 1.0f);  
  140.     checkGlError("glClearColor");  
  141.     glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);  
  142.     checkGlError("glClear");  
  143.   
  144.     glUseProgram(gProgram);  
  145.     checkGlError("glUseProgram");  
  146.   
  147.     glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);  
  148.     checkGlError("glVertexAttribPointer");  
  149.     glEnableVertexAttribArray(gvPositionHandle);  
  150.     checkGlError("glEnableVertexAttribArray");  
  151.     glDrawArrays(GL_TRIANGLES, 0, 3);  
  152.     checkGlError("glDrawArrays");  
  153. }  
  154.   
  155. extern "C" {  
  156.     JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height);  
  157.     JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj);  
  158. };  
  159.   
  160. JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)  
  161. {  
  162.     setupGraphics(width, height);  
  163. }  
  164.   
  165. JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)  
  166. {  
  167.     renderFrame();  
  168. }  


首先说几个C 的几个关键字的用法。


全局static变量与static函数

在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。
1)内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)
2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)
3)作用域:全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。

好处:
定义全局静态变量的好处:
1)不会被其他文件所访问,修改
2)其他文件中可以使用相同名字的变量,不会发生冲突。

静态函数
在函数的返回类型前加上关键字static,函数就被定义成为静态函数。
函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。
定义静态函数的好处:
<1> 其他文件中可以定义相同名字的函数,不会发生冲突
<2> 静态函数不能被其他文件所用。


extern "C" 的用法

被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;实现C 与C及其它语言的混合编程。

而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。

如果C 调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。

在这里用 extern "C"框住两个函数,主要是让Jni来调用它们。


代码分析

首先是在c 代码中打tag的方法。

  1. #include   
  2.   
  3. #define  LOG_TAG    "libgl2jni"  
  4. #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  5. #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  6.   
  7. static void printGLString(const char *name, GLenum s) {  
  8.     const char *v = (const char *) glGetString(s);  
  9.     LOGI("GL %s = %s\n", name, v);  
  10. }  

首先先是包含头log.h文件,

接下来是将自带的log函数用用预定义的方法简化一下。

printGLString等于是又封装了一层,同时可以打印gl的信息。


checkGlError用于检查OpenGL内部发生的错误,OpenGL在运行过程中所产生的错误都可以用glGetError来获得。


vertext shader和fregment shader的内容还有三角形的顶点位置都用已经在程序中写死。如果想加载外部的shader的话,要么在ndk中实现文件的读写,要么就在用java读取,然后传到C里面来处理。


shader相关的流水线可以参考 - GLSL入门


setupGraphics用于shader的一些初始化,还有context的一些初始化。

renderframe非常简单,就是渲染三角形,改变背景颜色,不断刷新。


http://blog.csdn.net/silangquan/article/details/39228203

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引