Android OpenGL ES 2.0画立方体JNI实现

前面实现了Android有关OpenGL ES 2.0的一些例子,现在,把它改成用JNI实现。

以立方体为例。代码主要变化发生在Renderer里,以前直接用JAVA的,现在都移到C++里了。

代码和JAVA的实质上是一样的。

下面来看看主要的代码。

先看看工程结构:

上代码。

OpenGLJniActivity.java:

 1 package com.jayce.eopengljni;
 2 
 3 import android.app.Activity;
 4 import android.app.ActivityManager;
 5 import android.content.Context;
 6 import android.content.pm.ConfigurationInfo;
 7 import android.opengl.GLSurfaceView;
 8 import android.os.Bundle;
 9 
10 public class OpenGLJniActivity extends Activity
11 {
12     private GLSurfaceView mGLSurfaceView;
13     
14     public void onCreate(Bundle savedInstanceState)
15     {
16         super.onCreate(savedInstanceState);
17         mGLSurfaceView = new GLSurfaceView(this);
18         final ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
19         final ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
20         if(configInfo.reqGlEsVersion >= 0x20000)
21         {
22             mGLSurfaceView.setEGLContextClientVersion(2);
23             OpenGLJniRenderer renderer = new OpenGLJniRenderer();
24             mGLSurfaceView.setRenderer(renderer);
25         }
26         
27         setContentView(mGLSurfaceView);
28     }
29     
30     @Override
31     protected void onResume() 
32     {
33         // The activity must call the GL surface view's onResume() on activity onResume().
34         super.onResume();
35         mGLSurfaceView.onResume();
36     }
37 
38     @Override
39     protected void onPause() 
40     {
41         // The activity must call the GL surface view's onPause() on activity onPause().
42         super.onPause();
43         mGLSurfaceView.onPause();
44     }    
45 }

上面这个和普通JAVA版的一模一样的。

然后是OpenGLJniRenderer.java:

 1 package com.jayce.eopengljni;
 2 
 3 import javax.microedition.khronos.egl.EGLConfig;
 4 import javax.microedition.khronos.opengles.GL10;
 5 import android.opengl.GLSurfaceView;
 6 
 7 public class OpenGLJniRenderer implements GLSurfaceView.Renderer
 8 {
 9     
10     @Override
11     public void onDrawFrame(GL10 gl) {
12         // TODO Auto-generated method stub
13         OpenGLJniLib.step();
14     }
15 
16     @Override
17     public void onSurfaceChanged(GL10 gl, int width, int height) {
18         OpenGLJniLib.init(width, height);
19     }
20 
21     @Override
22     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
23         OpenGLJniLib.create();
24     }
25 }

这个发生了不小的变化,主要的三个方法都换由C++实现了。

然后是native方法的包装类了。

OpenGLJniLib.java:

 1 package com.jayce.eopengljni;
 2 
 3 public class OpenGLJniLib {
 4 
 5      static {
 6          System.loadLibrary("gljni");
 7      }
 8 
 9      public static native void init(int width, int height);
10      public static native void create();
11      public static native void step();
12 }

然后主要工作都在C++里做了。

opengljni.cpp:

  1 #include <jni.h>
  2 #include <android/log.h>
  3 
  4 #include <GLES2/gl2.h>
  5 #include <GLES2/gl2ext.h>
  6 
  7 #include <stdio.h>
  8 #include <stdlib.h>
  9 #include <math.h>
 10 #include <string.h>
 11 #include "common/Matrix.h"
 12 
 13 #define  LOG_TAG    "libgljni"
 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 #define POSITION_DATA_SIZE 3
 18 #define COLOR_DATA_SIZE 4
 19 
 20 GLfloat gMVPMatrix[16] = {0.0f};
 21 GLfloat gViewMatrix[16] = {0.0f};
 22 GLfloat gModelMatrix[16] = {0.0f};
 23 GLfloat gProjectionMatrix[16] = {0.0f};
 24 
 25 GLuint gMVPMatrixHandle = 0;
 26 GLuint gPositionHandle = 0;
 27 GLuint gColorHandle = 0;
 28 GLuint gProgram = 0;
 29 
 30 const GLfloat cubePosition[] =
 31 {
 32     -1.0f, 1.0f, 1.0f,
 33     -1.0f, -1.0f, 1.0f,
 34     1.0f, 1.0f, 1.0f,
 35     -1.0f, -1.0f, 1.0f,
 36     1.0f, -1.0f, 1.0f,
 37     1.0f, 1.0f, 1.0f,
 38 
 39     1.0f, 1.0f, 1.0f,
 40     1.0f, -1.0f, 1.0f,
 41     1.0f, 1.0f, -1.0f,
 42     1.0f, -1.0f, 1.0f,
 43     1.0f, -1.0f, -1.0f,
 44     1.0f, 1.0f, -1.0f,
 45 
 46     1.0f, 1.0f, -1.0f,
 47     1.0f, -1.0f, -1.0f,
 48     -1.0f, 1.0f, -1.0f,
 49     1.0f, -1.0f, -1.0f,
 50     -1.0f, -1.0f, -1.0f,
 51     -1.0f, 1.0f, -1.0f,
 52 
 53     -1.0f, 1.0f, -1.0f,
 54     -1.0f, -1.0f, -1.0f,
 55     -1.0f, 1.0f, 1.0f,
 56     -1.0f, -1.0f, -1.0f,
 57     -1.0f, -1.0f, 1.0f,
 58     -1.0f, 1.0f, 1.0f,
 59 
 60     -1.0f, 1.0f, -1.0f,
 61     -1.0f, 1.0f, 1.0f,
 62     1.0f, 1.0f, -1.0f,
 63     -1.0f, 1.0f, 1.0f,
 64     1.0f, 1.0f, 1.0f,
 65     1.0f, 1.0f, -1.0f,
 66 
 67     1.0f, -1.0f, -1.0f,
 68     1.0f, -1.0f, 1.0f,
 69     -1.0f, -1.0f, -1.0f,
 70     1.0f, -1.0f, 1.0f,
 71     -1.0f, -1.0f, 1.0f,
 72     -1.0f, -1.0f, -1.0f
 73 };
 74 
 75 const GLfloat cubeColor[] =
 76 {
 77     1.0f, 0.0f, 0.0f, 1.0f,
 78     1.0f, 0.0f, 0.0f, 1.0f,
 79     1.0f, 0.0f, 0.0f, 1.0f,
 80     1.0f, 0.0f, 0.0f, 1.0f,
 81     1.0f, 0.0f, 0.0f, 1.0f,
 82     1.0f, 0.0f, 0.0f, 1.0f,
 83 
 84     0.0f, 1.0f, 0.0f, 1.0f,
 85     0.0f, 1.0f, 0.0f, 1.0f,
 86     0.0f, 1.0f, 0.0f, 1.0f,
 87     0.0f, 1.0f, 0.0f, 1.0f,
 88     0.0f, 1.0f, 0.0f, 1.0f,
 89     0.0f, 1.0f, 0.0f, 1.0f,
 90 
 91     0.0f, 0.0f, 1.0f, 1.0f,
 92     0.0f, 0.0f, 1.0f, 1.0f,
 93     0.0f, 0.0f, 1.0f, 1.0f,
 94     0.0f, 0.0f, 1.0f, 1.0f,
 95     0.0f, 0.0f, 1.0f, 1.0f,
 96     0.0f, 0.0f, 1.0f, 1.0f,
 97 
 98     1.0f, 1.0f, 0.0f, 1.0f,
 99     1.0f, 1.0f, 0.0f, 1.0f,
100     1.0f, 1.0f, 0.0f, 1.0f,
101     1.0f, 1.0f, 0.0f, 1.0f,
102     1.0f, 1.0f, 0.0f, 1.0f,
103     1.0f, 1.0f, 0.0f, 1.0f,
104 
105     0.0f, 1.0f, 1.0f, 1.0f,
106     0.0f, 1.0f, 1.0f, 1.0f,
107     0.0f, 1.0f, 1.0f, 1.0f,
108     0.0f, 1.0f, 1.0f, 1.0f,
109     0.0f, 1.0f, 1.0f, 1.0f,
110     0.0f, 1.0f, 1.0f, 1.0f,
111 
112     1.0f, 0.0f, 1.0f, 1.0f,
113     1.0f, 0.0f, 1.0f, 1.0f,
114     1.0f, 0.0f, 1.0f, 1.0f,
115     1.0f, 0.0f, 1.0f, 1.0f,
116     1.0f, 0.0f, 1.0f, 1.0f,
117     1.0f, 0.0f, 1.0f, 1.0f
118 };
119 
120 static const char gVertexShader[] =
121 {
122     "uniform mat4 u_MVPMatrix;      \n"
123     "attribute vec4 a_Position;     \n"
124     "attribute vec4 a_Color;        \n"
125 
126     "varying vec4 v_Color;          \n"
127 
128     "void main()                    \n"
129     "{                              \n"
130     "   v_Color = a_Color;          \n"
131     "   gl_Position = u_MVPMatrix   \n"
132     "               * a_Position;   \n"
133     "}                              \n"
134 };
135 
136 static const char gFragmentShader[] =
137 {
138     "precision mediump float;       \n"
139     "varying vec4 v_Color;          \n"
140     "void main()                    \n"
141     "{                              \n"
142     "   gl_FragColor = v_Color;     \n"
143     "}                              \n"
144 };
145 
146 GLuint loadShader(GLenum type, const char* source)
147 {
148     GLuint shader = glCreateShader(type);
149     if(shader)
150     {
151         glShaderSource(shader, 1, &source, NULL);
152         glCompileShader(shader);
153         GLint compileStatus = 0;
154         glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
155         if(!compileStatus)
156         {
157             GLint info_length = 0;
158             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_length);
159             if(info_length)
160             {
161                 char* buf = (char*)malloc(info_length * sizeof(char));
162                 if(buf)
163                 {
164                     glGetShaderInfoLog(shader, info_length, NULL, buf);
165                     LOGE("Create shader %d failed\n%s\n", type, buf);
166                 }
167             }
168             glDeleteShader(shader);
169             shader = 0;
170         }
171     }
172     return shader;
173 }
174 
175 GLuint createProgram(const char* pVertexSource, const char* pFragmentSource)
176 {
177     GLuint vshader = loadShader(GL_VERTEX_SHADER, pVertexSource);
178     if(!vshader)
179     {
180         return 0;
181     }
182     GLuint fshader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
183     if(!fshader)
184     {
185         return 0;
186     }
187     GLuint program = glCreateProgram();
188     if(program)
189     {
190         glAttachShader(program, vshader);
191         glAttachShader(program, fshader);
192         glBindAttribLocation(program, 0, "a_Position");
193         glBindAttribLocation(program, 1, "a_Color");
194 
195         glLinkProgram(program);
196 
197         GLint status = 0;
198         glGetProgramiv(program, GL_LINK_STATUS, &status);
199 
200         if(!status)
201         {
202             GLint info_length = 0;
203             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_length);
204             if(info_length)
205             {
206                 char* buf = (char*)malloc(info_length * sizeof(char));
207                 glGetProgramInfoLog(program, info_length, NULL, buf);
208                 LOGE("create program failed\n%s\n", buf);
209             }
210             glDeleteProgram(program);
211             program = 0;
212         }
213     }
214     return program;
215 }
216 
217 static GLfloat angleInDegrees = 0.1;
218 
219 void drawCube(const GLfloat* positions, const GLfloat* colors)
220 {
221     glVertexAttribPointer(gPositionHandle, POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, positions);
222     glEnableVertexAttribArray(gPositionHandle);
223     glVertexAttribPointer(gColorHandle, COLOR_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, colors);
224     glEnableVertexAttribArray(gColorHandle);
225     Matrix::multiplyMM(gMVPMatrix, 0, gViewMatrix, 0, gModelMatrix, 0);
226     Matrix::multiplyMM(gMVPMatrix, 0, gProjectionMatrix, 0, gMVPMatrix, 0);
227 
228     glUniformMatrix4fv(gMVPMatrixHandle, 1, GL_FALSE, gMVPMatrix);
229     glDrawArrays(GL_TRIANGLES, 0, 36);
230 }
231 
232 void renderFrame()
233 {
234     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
235     glUseProgram(gProgram);
236     gMVPMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
237     gPositionHandle = glGetAttribLocation(gProgram, "a_Position");
238     gColorHandle = glGetAttribLocation(gProgram, "a_Color");
239 
240     Matrix::setIdentityM(gModelMatrix, 0);
241     Matrix::translateM(gModelMatrix, 0, 0.0f, 0.0f, -5.0f);
242     if(359.0 <= angleInDegrees)
243     {
244         angleInDegrees = 0.1;
245     }
246     else
247     {
248         angleInDegrees = angleInDegrees + 1.0;
249     }
250 
251     Matrix::rotateM(gModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);
252 
253     drawCube(cubePosition, cubeColor);
254 }
255 
256 extern "C"
257 {
258     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object);
259     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height);
260     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object);
261 }
262 
263 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object)
264 {
265     LOGI("create");
266     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
267     glEnable(GL_CULL_FACE);
268     glEnable(GL_DEPTH_TEST);
269     const GLfloat eyeX = 0.0f;
270     const GLfloat eyeY = 0.0f;
271     const GLfloat eyeZ = -0.5f;
272 
273     const GLfloat lookX = 0.0f;
274     const GLfloat lookY = 0.0f;
275     const GLfloat lookZ = -5.0f;
276 
277     const GLfloat upX = 0.0f;
278     const GLfloat upY = 1.0f;
279     const GLfloat upZ = 0.0f;
280 
281     Matrix::setLookAtM(gViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
282     gProgram = createProgram(gVertexShader, gFragmentShader);
283 }
284 
285 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height)
286 {
287     LOGI("init");
288     glViewport(0, 0, width, height);
289     const GLfloat ratio = (GLfloat) width / height;
290     const GLfloat left = -ratio;
291     const GLfloat right = ratio;
292     const GLfloat bottom = -1.0f;
293     const GLfloat top = 1.0f;
294     const GLfloat near = 1.0f;
295     const GLfloat far = 10.0f;
296 
297     Matrix::frustumM(gProjectionMatrix, 0, left, right, bottom, top, near, far);
298 }
299 
300 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object)
301 {
302     LOGI("step");
303     renderFrame();
304 }

这里面实现了三个native方法,还有一些辅助的函数。

这里用到的Matrix类是我根据android源码里的Matrix类进行改写。

内容和Matrix.java大同小异,只是语法上的差异,功能和Matrix.java完全一样。

还有一点,Matrix类我里面有些有关数组越界的问题我没有做严格的检测,如果要运用在实际项目里应该加上的。

好了,下面就是Make文件了,很简单,参考NDK里的例子应该很容易写出来。

Android.mk:

 1 # Copyright (C) 2009 The Android Open Source Project
 2 #
 3 # Licensed under the Apache License, Version 2.0 (the "License");
 4 # you may not use this file except in compliance with the License.
 5 # You may obtain a copy of the License at
 6 #
 7 #      http://www.apache.org/licenses/LICENSE-2.0
 8 #
 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 LOCAL_PATH:= $(call my-dir)
16 
17 include $(CLEAR_VARS)
18 
19 LOCAL_MODULE    := gljni
20 LOCAL_CFLAGS    := -Werror
21 LOCAL_SRC_FILES := opengljni.cpp common/Matrix.cpp
22 LOCAL_LDLIBS    := -llog -lGLESv2
23 
24 include $(BUILD_SHARED_LIBRARY)

如果NDK环境已安好,ndk-build命令就能正确编译出库了。

当然,也可以用eclipse的NDK,cdt辅助,看个人喜好。

最后,效果图,是一个旋转的立方体,跟纯JAVA版的是完全一样的。

原文地址:https://www.cnblogs.com/jayceli/p/2564144.html