转自:http://blog.csdn.net/mnorst/article/details/39578909
大家好,我是无敌兔,从这一章开始讲在Android上进行Opengl ES 1.x的NDK开发实例,首先对这套开发实例教程的背景做一下说明。
Android SDK 提供了一套 OpenGL ES 接口,但该接口是基于 Java 的,速度非常慢,往往很难满足需要,所以采用NDK进行开发,底层的实现全部采用C++来编写。
该实例教程的java框架采用了Android NDK源码中的android-ndk-r9dsampleshello-gl2,开发实例的编写采用了《Nehe的OpenGL中文教程》中的例子。本实例教程重在演示如何在NDK框架下进行Opengl ES的编程,关于实例的原理大家可以参考《Nehe的OpenGL中文教程》,本教程中的实例基本上在《Nehe的OpenGL中文教程》中可以找到相应的解释。
《Nehe的OpenGL中文教程》的在线地址:Nehe的OpenGL中文教程
一、开发环境
Eclipse 3.7.1
android-sdk_r23.0.0-windows
android-ndk-r9d
cygwin 1.7.9
二、框架介绍
srccomandroidgljniGLJNIActivity.java 显示界面
srccomandroidgljniGLJNILib.java JNI库
srccomandroidgljniGLJNIView.java Opengl ES View
jniAndroid.mk NDK编译文件
jnigl_code.cpp JNI实现代码
三、实例介绍
GLJNIActivity.java
/*
* Copyright (C) 2007 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.
*
* author: mnorst@foxmail.com
*/
package com.android.gljni;
import com.android.gljni.GLJNIView;
import android.app.Activity;
import android.os.Bundle;
public class GLJNIActivity extends Activity {
GLJNIView mView;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mView = new GLJNIView(getApplication());
setContentView(mView);
}
@Override
protected void onPause() {
super.onPause();
mView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mView.onResume();
}
}
GLJNIView.java
/*
* Copyright (C) 2007 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.
*
* author: mnorst@foxmail.com
*/
package com.android.gljni;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.android.gljni.GLJNILib;
import android.content.Context;
import android.opengl.GLSurfaceView;
/**
* A simple GLSurfaceView sub-class that demonstrate how to perform
* OpenGL ES 1.x rendering into a GL Surface.
*/
public class GLJNIView extends GLSurfaceView {
private static final String LOG_TAG = GLJNIView.class.getSimpleName();
private Renderer renderer;
public GLJNIView(Context context) {
super(context);
// setEGLConfigChooser会对fps产生影响
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
renderer = new Renderer(context);
setRenderer(renderer);
}
private static class Renderer implements GLSurfaceView.Renderer {
public Renderer(Context ctx) {
}
public void onDrawFrame(GL10 gl) {
GLJNILib.step();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLJNILib.resize(width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLJNILib.init();
}
}
}
GLJNILib.java
/*
* Copyright (C) 2007 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.
*
* author: mnorst@foxmail.com
*/
package com.android.gljni;
//Wrapper for native library
public class GLJNILib {
static {
System.loadLibrary("gljni");
}
/**
* @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();
}
gl_code.cpp
/*
* Copyright (C) 2007 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.
*
* author: mnorst@foxmail.com
* created: 2014/09/26
* purpose: 搭建Opengl es 1.x NDK 开发框架
*/
// OpenGL ES 1.x code
#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 "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__)
// 定义π
const GLfloat PI = 3.1415f;
// 顶点数组
const GLfloat gVertices[] = {
0.0f, 1.0f, 0.0f,
-1.0f,-1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
};
/************************************************************************/
/* C++代码 */
/************************************************************************/
static void printGLString(const char *name, GLenum s) {
const char *v = (const char *) glGetString(s);
LOGI("GL %s = %s
", name, v);
}
static void checkGlError(const char* op) {
for (GLint error = glGetError(); error; error
= glGetError()) {
LOGI("after %s() glError (0x%x)
", 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;
}
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;
}
// 重置当前的视口
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);
// 选择模型观察矩阵
glMatrixMode(GL_MODELVIEW);
// 重置模型观察矩阵
glLoadIdentity();
}
void renderFrame() {
// 清除屏幕及深度缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置背景颜色为黑色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 重置当前的模型观察矩阵
glLoadIdentity();
// 移入屏幕 6.0
glTranslatef(0.0f,0.0f,-6.0f);
// 启用顶点数组
glEnableClientState(GL_VERTEX_ARRAY);
// 绘制三角形,图形的颜色默认为白色
glVertexPointer(3, GL_FLOAT, 0, gVertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
// 关闭顶点数组
glDisableClientState(GL_VERTEX_ARRAY);
}
/************************************************************************/
/* JNI代码 */
/************************************************************************/
extern "C" {
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height);
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj);
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj);
};
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_resize(JNIEnv * env, jobject obj, jint width, jint height)
{
resize(width, height);
}
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
{
renderFrame();
}
JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj)
{
init();
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgljni
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := gl_code.cpp
LOCAL_LDLIBS := -llog -lGLESv1_CM
include $(BUILD_SHARED_LIBRARY)