1. 程式人生 > >[Android NDK]Android JNI開發例子 ---3 在JNI中實現openGL功能

[Android NDK]Android JNI開發例子 ---3 在JNI中實現openGL功能

這個例子使用native部分來實現opengl es而不是java部分。

Java部分與例子2相似。

MainActivity.java

public class MainActivity extends Activity {

    GLSurfaceView mGLView;
    static {
        System.loadLibrary("myegl_jni");
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN); // (NEW)

        this.mGLView = new MyGLSurfaceView(this);  
        setContentView(this.mGLView);
    }
}

MyGLSurfaceView.java
public class MyGLSurfaceView extends GLSurfaceView {

    GLSurfaceView.Renderer mRenderer;
    private boolean goNative;

    /**
     * TODO Put here a description of what this constructor does.
     * 
     * @param context
     * @param goNative
     */
    public MyGLSurfaceView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub.
        mRenderer = new MyRenderer();
        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(mRenderer);
    }
}
Renderer.java
public class MyRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "agl";

    private native String nativeGetHelloString();

    private native void nativeDrawFrame();

    private native void nativeSurfaceChanged(int width, int height);

    private native void nativeSurfaceCreated();

    @Override
    public void onDrawFrame(GL10 gl) {
       nativeDrawFrame();
        Log.d(TAG, "onDrawFrame " + nativeGetHelloString());
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        nativeSurfaceChanged(width,height);
        Log.d(TAG, "onSurfaceChanged");
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        nativeSurfaceCreated();
        Log.d(TAG, "onSurfaceCreate");
    }
}

在jni資料夾內建立include資料夾。 在include下建立一個頭檔案。cpp中的所有變數和函式要在宣告之後才能夠直接使用。 .h檔案中都是宣告。
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include <GLES/gl.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

extern "C" {
#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__)
#define  LOGD(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

void printGLString(char* name, GLenum s);
void init();
void resize(int width, int height);
void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
void renderFrame();

GLfloat rtri;  //三角形的旋轉變數

GLfloat rquad;  //四邊形的旋轉變數

const GLfloat PI = 3.1415f;

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
};

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
};
} //end of extern "C"

cpp檔案
#include "com_example_nativeegl_MyRenderer.h"

extern "C" {

 void printGLString(char* name, GLenum s) {
	char *v = (char *) glGetString(s);
	LOGI("GL %s = %s", name, v);
}

/*
 * Class:     com_example_nativeegl_MyRenderer
 * Method:    nativeGetHelloString
 * Signature: ()Ljava/lang/String;
 */
jstring  nativeGetHelloString(JNIEnv *env, jobject obj) {
      return env->NewStringUTF((char*)" This is calling from JNI suckers!");
  }

/*
 * Class:     com_example_nativeegl_MyRenderer
 * Method:    nativeDrawFrame
 * Signature: ()V
 */
void nativeDrawFrame(JNIEnv *env, jobject obj) {
	renderFrame();
}

/*
 * Class:     com_example_nativeegl_MyRenderer
 * Method:    nativeSurfaceChanged
 * Signature: (II)V
 */
void nativeSurfaceChanged(JNIEnv *env, jobject obj, jint width, jint height){
	resize(width, height);
}

void init() {
	LOGD("init the renderer");
	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);
}

void resize(int width, int height) {
	LOGD("resize the renderer");
	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 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 renderFrame() {
	LOGD("renderFrame the renderer");
	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();
}

/*
 * Class:     com_example_nativeegl_MyRenderer
 * Method:    nativeSurfaceCreated
 * Signature: ()V
 */
 void nativeSurfaceCreated(JNIEnv *env, jobject obj) {
	 init();
 }

//----------------------------JNI part:Native register------------------------------------------------------
static JNINativeMethod gMethods[] = {
		//{"native method name from Java","(arguments type)return type", "(void*)local_native_name"
		{"nativeGetHelloString", "()Ljava/lang/String;", (void *)nativeGetHelloString},
		{"nativeDrawFrame", "()V", (void *)nativeDrawFrame},
		{"nativeSurfaceChanged", "(II)V", (void *)nativeSurfaceChanged},
		{"nativeSurfaceCreated", "()V", (void *)nativeSurfaceCreated},
};

static const char* className="com/example/nativeegldynamicjni/MyRenderer";

static int registerNativeMethods(JNIEnv *env) {
	jclass clazz;
	clazz = env->FindClass(className);
	if (clazz == NULL) {
		LOGD("failed to load the class %s", className);
		return JNI_FALSE;
	}
	if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {
		return JNI_FALSE;
	}
	return JNI_TRUE;
} //end of registerNativeMethods

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env = NULL;
	jint result = -1;
	if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
	{
		LOGE("ERROR: GetEnv failed\n");
		goto bail;
	}

	if (registerNativeMethods(env) < 0) {
		LOGE("ERROR: jnitest native registration failed\n");
		goto bail;
	}
	result = JNI_VERSION_1_4;

	bail:
	return result;
}

} //end of extern "C"

Android.mk
#Description:makefile of Helloworld  
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS    := -Wall
LOCAL_MODULE    := myegl_jni
LOCAL_C_INCLUDES :=$(LOCAL_PATH)/include
LOCAL_CPP_EXTENSION := .cpp
LOCAL_LDLIBS += -llog -lGLESv1_CM
LOCAL_SRC_FILES := com_example_nativeegl_MyRenderer.cpp

include $(BUILD_SHARED_LIBRARY)

在專案根目錄想執行ndk-build編譯jni出.so庫。