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版的是完全一樣的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM