Android
SDK 提供了一套 OpenGL ES 接口,该接口是基于 Java 的,速度非常 慢,往往很难满足需要。写此文章的目的是为了使用Android
提供的NDK 工具来使用C/C++ 原生代码。因最近在研究Android OpenGL ES 部分,就以使用C++ 来书写opengles 代码, 然后通过JNI 提供给java调用。重要的是避免了调用Android SDK OpenGL
ES 接口,是速度大大提高 。
首先告知大家我使用的平台:(本文将省略如何安装Eclipse ,ADT,及如何配置Android sdk等..)
Linux Fedora 12 ,Eclipse Helios版本,Android SDK 2.2,Android
NDK r4(目前最新)
NDK r4(目前最新)
安装NDK: 首先去官网下载Android
NDK ,在此给提供一个免翻墙的网站: http://androidappdocs.appspot.com/sdk/ndk/index.html ,并将其加压到任意目录(后文以#NDK
来代表解压目录)
NDK ,在此给提供一个免翻墙的网站: http://androidappdocs.appspot.com/sdk/ndk/index.html ,并将其加压到任意目录(后文以#NDK
来代表解压目录)
本文不会大多关注代码部分的讲解,我会将主要代码贴出,并在此文的提供给大家源码下载.文中有关于android.mk 代码的编写,可自行参考#NDK/doc/ANDROID-MK.TXT 文档。
1,在Eclipse 下新建Android 项目 (名字:OpenGl_Jni 包:com.opengl.jni) 新建以下四个类
Activity 类 :
package com.opengl.jni;
import android.app.Activity;
import android.os.Bundle;
public class GLActivity extends Activity {
/** Called when the activity is first created. */
private GLCanvas mCanvas;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCanvas = new GLCanvas(getApplication());
setContentView(mCanvas);
}
...........................
}
GlCanvas 类继承GLSurfaceView类:
package com.opengl.jni;
public class GLCanvas extends GLSurfaceView {
private static final String TAG = "GLCanvas";
private static final boolean DEBUG = false;
public GLCanvas(Context context) {
super(context);
// TODO Auto-generated constructor stub
init(false, 0, 0);
}
public GLCanvas(Context context, boolean translucent, int depth, int stencil) {
super(context);
init(translucent, depth, stencil);
}
................
}
GLRenderer 类实现GLSurfaceView.Renderer 接口 :如下
public class GLRenderer implements GLSurfaceView.Renderer{
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
GLJniLib.step();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
GLJniLib.init(width, height);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
}
}
GLJniLib 类 :
package com.opengl.jni;
public class GLJniLib {
static {
System.loadLibrary("gljni");
}
/**
* @param width the current view width
* @param height the current view height
*/
public static native void init(int width, int height);
public static native void step();
public static native void setBackColor(float r,float g,float b);
}
2,在OpenGl_Jni项目根目录下 新建jni 文件夹 ,并在jni 文件夹下 建立Android.mk 及gl_code.cpp 文件 ,如下:
Anddroid.mk 内容如下 :
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgljni
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := gl_code.cpp
LOCAL_LDLIBS := -llog -lGLESv2
include $(BUILD_SHARED_LIBRARY)
gl_code.cpp 内容如下 :
// OpenGL ES 2.0 code
#include <jni.h>
#include <android/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.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);
}
}
static const char gVertexShader[] = "attribute vec4 vPosition;\n"
"void main() {\n"
" gl_Position = vPosition;\n"
"}\n";
static const char gFragmentShader[] = "precision mediump float;\n"
"void main() {\n"
" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
"}\n";
GLuint loadShader(GLenum shaderType, const char* pSource) {
GLuint shader = glCreateShader(shaderType);
if (shader) {
glShaderSource(shader, 1, &pSource, NULL);
glCompileShader(shader);
GLint compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen) {
char* buf = (char*) malloc(infoLen);
if (buf) {
glGetShaderInfoLog(shader, infoLen, NULL, buf);
LOGE("Could not compile shader %d:\n%s\n",
shaderType, buf);
free(buf);
}
glDeleteShader(shader);
shader = 0;
}
}
}
return shader;
}
GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
if (!vertexShader) {
return 0;
}
GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
if (!pixelShader) {
return 0;
}
GLuint program = glCreateProgram();
if (program) {
glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
glAttachShader(program, pixelShader);
checkGlError("glAttachShader");
glLinkProgram(program);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
GLint bufLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength) {
char* buf = (char*) malloc(bufLength);
if (buf) {
glGetProgramInfoLog(program, bufLength, NULL, buf);
LOGE("Could not link program:\n%s\n", buf);
free(buf);
}
}
glDeleteProgram(program);
program = 0;
}
}
return program;
}
GLuint gProgram;
GLuint gvPositionHandle;
bool setupGraphics(int w, int h) {
printGLString("Version", GL_VERSION);
printGLString("Vendor", GL_VENDOR);
printGLString("Renderer", GL_RENDERER);
printGLString("Extensions", GL_EXTENSIONS);
LOGI("setupGraphics(%d, %d)", w, h);
gProgram = createProgram(gVertexShader, gFragmentShader);
if (!gProgram) {
LOGE("Could not create program.");
return false;
}
gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
checkGlError("glGetAttribLocation");
LOGI("glGetAttribLocation(\"vPosition\") = %d\n",
gvPositionHandle);
glViewport(0, 0, w, h);
checkGlError("glViewport");
return true;
}
const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f };
GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f};
// by gaoxi.xie
float _red = 0.9f;
float _green = 0.2f;
float _blue = 0.2f;
void setBackColor(float r, float g, float b) {
_red = r;
_green = g;
_blue = b;
}
void renderFrame() {
static float grey;
grey += 0.01f;
if (grey > 1.0f) {
grey = 0.0f;
}
glClearColor(grey, grey, grey, 1.0f);
checkGlError("glClearColor");
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
checkGlError("glClear");
glUseProgram(gProgram);
checkGlError("glUseProgram");
glVertexAttribPointer(gvPositionHandle, 2