我们可以在jni层上编写opengl代码, 进行3d 图形的绘制,下面这个例子就是在一个绘制四面体的例子, 实例的绘制代码是在jni层实现的, 采用c++语言编写。
1. 首先, 创建上层应用程序相关类, 组织好调用路径。
这里主要是创建活动类, 渲染类以及相关辅助类。
主活动类代码如下:
import android.app.Activity;
import android.os.Bundle;
public class GL10JNIActivity extends Activity {
private GL10JNIView mView;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mView = new GL10JNIView(this);
setContentView(mView);
}
@Override
protected void onPause() {
super.onPause();
mView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mView.onResume();
}
}
其次创建opengl视图类,代码如下:
import android.content.Context;
import android.opengl.GLSurfaceView;
public class GL10JNIView extends GLSurfaceView {
private static final String LOG_TAG = GL10JNIView.class.getSimpleName();
private MyRenderer myRenderer;
public GL10JNIView(Context context) {
super(context);
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
myRenderer = new MyRenderer(context);
setRenderer(myRenderer);
}
}
接着创建渲染类,代码如下:
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
public class MyRenderer implements Renderer {
public MyRenderer(Context ctx) {
}
@Override
public void onDrawFrame(GL10 gl) {
GL10JNILib.step();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GL10JNILib.resize(width, height);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GL10JNILib.init();
}
}
最后,声明与jni 相对应的本地化方法, 加载相应的jni代码生成的库, 代码如下:
public class GL10JNILib {
static {
System.loadLibrary("gl10jni");
}
/**
* @param width the current view width
* @param height the current view height
*/
public static native void resize(int width, int height);
public static native void step();
public static native void init();
}
2. 编写jni绘制代码
在android工程的根目录下创建jni 文件夹, 新建两个文件, 一个是Android.mk文件,另一个就是我们实现绘制的代码文件,其中Android.mk文件的内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgl10jni
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := gl_code.cpp
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)
最后是相应的绘制代码,如下所示:
#include <jni.h>
#include <android/log.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LOG_TAG "libgl2jni"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static void printGLString(const char *name, GLenum s) {
const char *v = (const char *) glGetString(s);
LOGI("GL %s = %s\n", name, v);
}
static void checkGlError(const char* op) {
for (GLint error = glGetError(); error; error
= glGetError()) {
LOGI("after %s() glError (0x%x)\n", op, error);
}
}
bool init() {
printGLString("Version", GL_VERSION);
printGLString("Vendor", GL_VENDOR);
printGLString("Renderer", GL_RENDERER);
printGLString("Extensions", GL_EXTENSIONS);
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 黑色背景
glClearDepthf(1.0f); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统对透视进行修正
return true;
}
const GLfloat gVertices[] = {
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f,-1.0f, 1.0f,
1.0f,-1.0f, -1.0f,
0.0f, 1.0f, 0.0f,
1.0f,-1.0f, -1.0f,
-1.0f,-1.0f, -1.0f,
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f,-1.0f,
-1.0f,-1.0f, 1.0f
};
const GLfloat gColors[] = {
1.0f,0.0f,0.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
1.0f,0.0f,0.0f, 1.0f,
0.0f,0.0f,1.0f, 1.0f,
0.0f,1.0f,0.0f, 1.0f
};
static GLfloat rtri; //三角形的旋转变量
static GLfloat rquad; //四边形的旋转变量
const GLfloat PI = 3.1415f;
static void _gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
{
GLfloat top = zNear * ((GLfloat) tan(fovy * PI / 360.0));
GLfloat bottom = -top;
GLfloat left = bottom * aspect;
GLfloat right = top * aspect;
glFrustumf(left, right, bottom, top, zNear, zFar);
}
void resize(int width, int height)
{
if (height==0) // 防止被零除
{
height=1; // 将Height设为1
}
glViewport(0, 0, width, height); // 重置当前的视口
glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵
GLfloat ratio = (GLfloat)width/(GLfloat)height;
// 设置视口的大小
_gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
// glOrthof(-2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f);
glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
}
void renderFrame() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕及深度缓存
glLoadIdentity(); // 重置模型观察矩阵
glTranslatef(0.0f,0.0f, -6.0f); // 移入屏幕 6.0
glRotatef(rtri,0.0f,1.0f,0.0f); // 绕Y轴旋转金字塔
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, gColors);
glVertexPointer(3, GL_FLOAT, 0, gVertices);
glDrawArrays(GL_TRIANGLES, 0, 12);
rtri += 0.2f; // 增加三角形的旋转变量
//LOGI("xxxxx");
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glFlush();
}
extern "C" {
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_resize(JNIEnv * env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_step(JNIEnv * env, jobject obj);
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_init(JNIEnv * env, jobject obj);
};
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_resize(JNIEnv * env, jobject obj, jint width, jint height)
{
resize(width, height);
}
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_step(JNIEnv * env, jobject obj)
{
renderFrame();
}
JNIEXPORT void JNICALL Java_com_test_fuyajun_GL10JNILib_init(JNIEnv * env, jobject obj)
{
init();
}
利用ndk-build工具将jni代码编译成库, 然后运行android 应用程序即可。