Android OpenGL ES 2.0画立方体JNI实现

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

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

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

下面来看看主要的代码。

先看看工程结构:

上代码。

OpenGLJniActivity.java:

package com.jayce.eopengljni;
 
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.ConfigurationInfo;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
 
 public class OpenGLJniActivity extends Activity
 {
     private GLSurfaceView mGLSurfaceView;
     
     public void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
         mGLSurfaceView = new GLSurfaceView(this);
         final ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
         final ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
         if(configInfo.reqGlEsVersion >= 0x20000)
         {
             mGLSurfaceView.setEGLContextClientVersion(2);
             OpenGLJniRenderer renderer = new OpenGLJniRenderer();
             mGLSurfaceView.setRenderer(renderer);
         }
         
         setContentView(mGLSurfaceView);
     }
     
     @Override
     protected void onResume() 
     {
         // The activity must call the GL surface view's onResume() on activity onResume().
         super.onResume();
         mGLSurfaceView.onResume();
     }
 
     @Override
     protected void onPause() 
     {
         // The activity must call the GL surface view's onPause() on activity onPause().
         super.onPause();
         mGLSurfaceView.onPause();
     }    
 }

上面这个和普通JAVA版的一模一样的。然后是OpenGLJniRenderer.java:

package com.jayce.eopengljni;
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 import android.opengl.GLSurfaceView;
 
 public class OpenGLJniRenderer implements GLSurfaceView.Renderer
 {
     
     @Override
     public void onDrawFrame(GL10 gl) {
         // TODO Auto-generated method stub
         OpenGLJniLib.step();
     }
 
     @Override
     public void onSurfaceChanged(GL10 gl, int width, int height) {
         OpenGLJniLib.init(width, height);
     }
 
     @Override
     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
         OpenGLJniLib.create();
     }
 }

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

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

OpenGLJniLib.java:

package com.jayce.eopengljni;
 
 public class OpenGLJniLib {
 
      static {
          System.loadLibrary("gljni");
      }
 
      public static native void init(int width, int height);
      public static native void create();
      public static native void step();
 }

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

opengljni.cpp:

#include <jni.h>
 #include <android/log.h>
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
 #include <string.h>
 #include "common/Matrix.h"
 
 #define  LOG_TAG    "libgljni"
 #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
 #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
 
 #define POSITION_DATA_SIZE 3
 #define COLOR_DATA_SIZE 4
 
 GLfloat gMVPMatrix[16] = {0.0f};
 GLfloat gViewMatrix[16] = {0.0f};
 GLfloat gModelMatrix[16] = {0.0f};
 GLfloat gProjectionMatrix[16] = {0.0f};
 
 GLuint gMVPMatrixHandle = 0;
 GLuint gPositionHandle = 0;
 GLuint gColorHandle = 0;
 GLuint gProgram = 0;
 
 const GLfloat cubePosition[] =
 {
     -1.0f, 1.0f, 1.0f,
     -1.0f, -1.0f, 1.0f,
     1.0f, 1.0f, 1.0f,
     -1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, 1.0f,
     1.0f, 1.0f, 1.0f,
 
     1.0f, 1.0f, 1.0f,
     1.0f, -1.0f, 1.0f,
     1.0f, 1.0f, -1.0f,
     1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, -1.0f,
     1.0f, 1.0f, -1.0f,
 
     1.0f, 1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
     -1.0f, 1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
     -1.0f, -1.0f, -1.0f,
     -1.0f, 1.0f, -1.0f,
 
     -1.0f, 1.0f, -1.0f,
     -1.0f, -1.0f, -1.0f,
     -1.0f, 1.0f, 1.0f,
     -1.0f, -1.0f, -1.0f,
     -1.0f, -1.0f, 1.0f,
     -1.0f, 1.0f, 1.0f,
 
     -1.0f, 1.0f, -1.0f,
     -1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, -1.0f,
     -1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, -1.0f,
 
     1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, 1.0f,
     -1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, 1.0f,
     -1.0f, -1.0f, 1.0f,
     -1.0f, -1.0f, -1.0f
 };
 
 const GLfloat cubeColor[] =
 {
     1.0f, 0.0f, 0.0f, 1.0f,
     1.0f, 0.0f, 0.0f, 1.0f,
     1.0f, 0.0f, 0.0f, 1.0f,
     1.0f, 0.0f, 0.0f, 1.0f,
     1.0f, 0.0f, 0.0f, 1.0f,
     1.0f, 0.0f, 0.0f, 1.0f,
 
     0.0f, 1.0f, 0.0f, 1.0f,
     0.0f, 1.0f, 0.0f, 1.0f,
     0.0f, 1.0f, 0.0f, 1.0f,
     0.0f, 1.0f, 0.0f, 1.0f,
     0.0f, 1.0f, 0.0f, 1.0f,
     0.0f, 1.0f, 0.0f, 1.0f,
 
     0.0f, 0.0f, 1.0f, 1.0f,
     0.0f, 0.0f, 1.0f, 1.0f,
     0.0f, 0.0f, 1.0f, 1.0f,
     0.0f, 0.0f, 1.0f, 1.0f,
     0.0f, 0.0f, 1.0f, 1.0f,
     0.0f, 0.0f, 1.0f, 1.0f,
 
     1.0f, 1.0f, 0.0f, 1.0f,
     1.0f, 1.0f, 0.0f, 1.0f,
     1.0f, 1.0f, 0.0f, 1.0f,
     1.0f, 1.0f, 0.0f, 1.0f,
     1.0f, 1.0f, 0.0f, 1.0f,
     1.0f, 1.0f, 0.0f, 1.0f,
 
     0.0f, 1.0f, 1.0f, 1.0f,
     0.0f, 1.0f, 1.0f, 1.0f,
     0.0f, 1.0f, 1.0f, 1.0f,
     0.0f, 1.0f, 1.0f, 1.0f,
     0.0f, 1.0f, 1.0f, 1.0f,
     0.0f, 1.0f, 1.0f, 1.0f,
 
     1.0f, 0.0f, 1.0f, 1.0f,
     1.0f, 0.0f, 1.0f, 1.0f,
     1.0f, 0.0f, 1.0f, 1.0f,
     1.0f, 0.0f, 1.0f, 1.0f,
     1.0f, 0.0f, 1.0f, 1.0f,
     1.0f, 0.0f, 1.0f, 1.0f
 };
 
 static const char gVertexShader[] =
 {
     "uniform mat4 u_MVPMatrix;      \n"
     "attribute vec4 a_Position;     \n"
     "attribute vec4 a_Color;        \n"
 
     "varying vec4 v_Color;          \n"
 
     "void main()                    \n"
     "{                              \n"
     "   v_Color = a_Color;          \n"
     "   gl_Position = u_MVPMatrix   \n"
     "               * a_Position;   \n"
     "}                              \n"
 };
 
 static const char gFragmentShader[] =
 {
     "precision mediump float;       \n"
     "varying vec4 v_Color;          \n"
     "void main()                    \n"
     "{                              \n"
     "   gl_FragColor = v_Color;     \n"
     "}                              \n"
 };
 
 GLuint loadShader(GLenum type, const char* source)
 {
     GLuint shader = glCreateShader(type);
     if(shader)
     {
         glShaderSource(shader, 1, &source, NULL);
         glCompileShader(shader);
         GLint compileStatus = 0;
         glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
         if(!compileStatus)
         {
             GLint info_length = 0;
             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_length);
             if(info_length)
             {
                 char* buf = (char*)malloc(info_length * sizeof(char));
                 if(buf)
                 {
                     glGetShaderInfoLog(shader, info_length, NULL, buf);
                     LOGE("Create shader %d failed\n%s\n", type, buf);
                 }
             }
             glDeleteShader(shader);
             shader = 0;
         }
     }
     return shader;
 }
 
 GLuint createProgram(const char* pVertexSource, const char* pFragmentSource)
 {
     GLuint vshader = loadShader(GL_VERTEX_SHADER, pVertexSource);
     if(!vshader)
     {
         return 0;
     }
     GLuint fshader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
     if(!fshader)
     {
         return 0;
     }
     GLuint program = glCreateProgram();
     if(program)
     {
         glAttachShader(program, vshader);
         glAttachShader(program, fshader);
         glBindAttribLocation(program, 0, "a_Position");
         glBindAttribLocation(program, 1, "a_Color");
 
         glLinkProgram(program);
 
         GLint status = 0;
         glGetProgramiv(program, GL_LINK_STATUS, &status);
 
         if(!status)
         {
             GLint info_length = 0;
             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_length);
             if(info_length)
             {
                 char* buf = (char*)malloc(info_length * sizeof(char));
                 glGetProgramInfoLog(program, info_length, NULL, buf);
                 LOGE("create program failed\n%s\n", buf);
             }
             glDeleteProgram(program);
             program = 0;
         }
     }
     return program;
 }
 
 static GLfloat angleInDegrees = 0.1;
 
 void drawCube(const GLfloat* positions, const GLfloat* colors)
 {
     glVertexAttribPointer(gPositionHandle, POSITION_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, positions);
     glEnableVertexAttribArray(gPositionHandle);
     glVertexAttribPointer(gColorHandle, COLOR_DATA_SIZE, GL_FLOAT, GL_FALSE, 0, colors);
     glEnableVertexAttribArray(gColorHandle);
     Matrix::multiplyMM(gMVPMatrix, 0, gViewMatrix, 0, gModelMatrix, 0);
     Matrix::multiplyMM(gMVPMatrix, 0, gProjectionMatrix, 0, gMVPMatrix, 0);
 
     glUniformMatrix4fv(gMVPMatrixHandle, 1, GL_FALSE, gMVPMatrix);
     glDrawArrays(GL_TRIANGLES, 0, 36);
 }
 
 void renderFrame()
 {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glUseProgram(gProgram);
     gMVPMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
     gPositionHandle = glGetAttribLocation(gProgram, "a_Position");
     gColorHandle = glGetAttribLocation(gProgram, "a_Color");
 
     Matrix::setIdentityM(gModelMatrix, 0);
     Matrix::translateM(gModelMatrix, 0, 0.0f, 0.0f, -5.0f);
     if(359.0 <= angleInDegrees)
     {
         angleInDegrees = 0.1;
     }
     else
     {
         angleInDegrees = angleInDegrees + 1.0;
     }
 
     Matrix::rotateM(gModelMatrix, 0, angleInDegrees, 1.0f, 1.0f, 0.0f);
 
     drawCube(cubePosition, cubeColor);
 }
 
 extern "C"
 {
     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object);
     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height);
     JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object);
 }
 
 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_create(JNIEnv * env, jobject object)
 {
     LOGI("create");
     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     glEnable(GL_CULL_FACE);
     glEnable(GL_DEPTH_TEST);
     const GLfloat eyeX = 0.0f;
     const GLfloat eyeY = 0.0f;
     const GLfloat eyeZ = -0.5f;
 
     const GLfloat lookX = 0.0f;
     const GLfloat lookY = 0.0f;
     const GLfloat lookZ = -5.0f;
 
     const GLfloat upX = 0.0f;
     const GLfloat upY = 1.0f;
     const GLfloat upZ = 0.0f;
 
     Matrix::setLookAtM(gViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
     gProgram = createProgram(gVertexShader, gFragmentShader);
 }
 
 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_init(JNIEnv * env, jobject object, jint width, jint height)
 {
     LOGI("init");
     glViewport(0, 0, width, height);
     const GLfloat ratio = (GLfloat) width / height;
     const GLfloat left = -ratio;
     const GLfloat right = ratio;
     const GLfloat bottom = -1.0f;
     const GLfloat top = 1.0f;
     const GLfloat near = 1.0f;
     const GLfloat far = 10.0f;
 
     Matrix::frustumM(gProjectionMatrix, 0, left, right, bottom, top, near, far);
 }
 
 JNIEXPORT void JNICALL Java_com_jayce_eopengljni_OpenGLJniLib_step(JNIEnv * env, jobject object)
 {
     LOGI("step");
     renderFrame();
 }

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

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

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

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

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

Android.mk:

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

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

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

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



转贴:http://www.cnblogs.com/jayceli/archive/2012/06/26/2564144.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值