OpenGL ES 3.0 上的一个三角形例子,网上可以下载到android skd 版(java)和 android ndk (c&c++版)
为了了解一下JNI,于是写了如下小程序。
这个例子是使用jni, java中调用c中的代码完成三角形的渲染, 其中shader代码保存在assets目录下,如下目录图:
其中,com_jnirenderer_RendererJNI.h 是 使用javah命令生成的,进入bin/classes目录下运行如下命令:
javah -classpath "D:\Program Files (x86)\Android\android-sdk\platforms\android-20\android.jar";. -jni PackageName.ClassName (注意路径、包名以及类名的替换)
MainActivity.java代码如下:
package com.jnirenderer; 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; import android.util.Log; public class MainActivity extends Activity { private final int CONTEXT_CLIENT_VERSION = 3; private GLSurfaceView mGLSurfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLSurfaceView = new GLSurfaceView(this); if (detectOpenGLES30()) { mGLSurfaceView.setEGLContextClientVersion(CONTEXT_CLIENT_VERSION); mGLSurfaceView.setRenderer(new RendererJNI(this)); } else { Log.e("opengles30", "OpenGL ES 3.0 not supported on device. Exiting..."); finish(); } setContentView(mGLSurfaceView); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); mGLSurfaceView.onResume(); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); mGLSurfaceView.onPause(); } private boolean detectOpenGLES30() { ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); ConfigurationInfo info = am.getDeviceConfigurationInfo(); return (info.reqGlEsVersion >= 0x30000); } }
package com.jnirenderer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.content.res.AssetManager; import android.opengl.GLSurfaceView; import android.util.Log; public class RendererJNI implements GLSurfaceView.Renderer { static { System.loadLibrary("JNIOpenGLES30"); } private AssetManager mAssetMgr = null; private final String mLogTag = "ndk-build"; public native void glesInit(); public native void glesRender(); public native void glesResize(int width, int height); public native void readShaderFile(AssetManager assetMgr); public RendererJNI(Context context) { mAssetMgr = context.getAssets(); if (null == mAssetMgr) { Log.e(mLogTag, "getAssets() return null !"); } } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub readShaderFile(mAssetMgr); glesInit(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub glesResize(width, height); } @Override public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub glesRender(); } }
#include "com_jnirenderer_RendererJNI.h" #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <GLES3/gl3.h> #include <android/asset_manager_jni.h> #include <android/log.h> #define LOG_TAG "ndk-build" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) GLint g_programObject; jint g_width; jint g_height; AAssetManager* g_pAssetManager = NULL; char* readShaderSrcFile(char *shaderFile, AAssetManager *pAssetManager) { AAsset *pAsset = NULL; char *pBuffer = NULL; off_t size = -1; int numByte = -1; if (NULL == pAssetManager) { LOGE("pAssetManager is null!"); return NULL; } pAsset = AAssetManager_open(pAssetManager, shaderFile, AASSET_MODE_UNKNOWN); //LOGI("after AAssetManager_open"); size = AAsset_getLength(pAsset); LOGI("after AAssetManager_open"); pBuffer = (char *)malloc(size+1); pBuffer[size] = '\0'; numByte = AAsset_read(pAsset, pBuffer, size); LOGI("%s : [%s]", shaderFile, pBuffer); AAsset_close(pAsset); return pBuffer; } GLuint LoadShader ( GLenum type, const char *shaderSrc ) { GLuint shader; GLint compiled; // Create the shader object shader = glCreateShader ( type ); if ( shader == 0 ) { return 0; } // Load the shader source glShaderSource ( shader, 1, &shaderSrc, NULL ); // Compile the shader glCompileShader ( shader ); // Check the compile status glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); if ( !compiled ) { GLint infoLen = 0; glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); if ( infoLen > 1 ) { char *infoLog = malloc ( sizeof ( char ) * infoLen ); glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); LOGE("Error compiling shader:[%s]", infoLog ); free ( infoLog ); } glDeleteShader ( shader ); return 0; } return shader; } //********************************************************************************* // JNIEXPORT void JNICALL Java_com_jnirenderer_RendererJNI_readShaderFile(JNIEnv *env, jobject self, jobject assetManager) { if (assetManager && env) { //LOGI("before AAssetManager_fromJava"); g_pAssetManager = AAssetManager_fromJava(env, assetManager); //LOGI("after AAssetManager_fromJava"); if (NULL == g_pAssetManager) { LOGE("AAssetManager_fromJava() return null !"); } } else { LOGE("assetManager is null !"); } } //********************************************************************************* // JNIEXPORT void JNICALL Java_com_jnirenderer_RendererJNI_glesInit(JNIEnv *pEnv, jobject obj) { char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "} \n"; char fShaderStr[] = "#version 300 es \n" "precision mediump float; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n" "} \n"; char *pVertexShader = readShaderSrcFile("shader/vs.glsl", g_pAssetManager); char *pFragmentShader = readShaderSrcFile("shader/fs.glsl", g_pAssetManager); GLuint vertexShader; GLuint fragmentShader; GLuint programObject; GLint linked; // Load the vertex/fragment shaders //vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr ); //fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr ); vertexShader = LoadShader ( GL_VERTEX_SHADER, pVertexShader ); fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, pFragmentShader ); // Create the program object programObject = glCreateProgram ( ); if ( programObject == 0 ) { return; } glAttachShader ( programObject, vertexShader ); glAttachShader ( programObject, fragmentShader ); // Link the program glLinkProgram ( programObject ); // Check the link status glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); if ( !linked ) { GLint infoLen = 0; glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); if ( infoLen > 1 ) { char *infoLog = malloc ( sizeof ( char ) * infoLen ); glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); LOGE("Error linking program:[%s]", infoLog ); free ( infoLog ); } glDeleteProgram ( programObject ); return; } // Store the program object g_programObject = programObject; glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f ); } //********************************************************************************* // JNIEXPORT void JNICALL Java_com_jnirenderer_RendererJNI_glesRender(JNIEnv *pEnv, jobject obj) { GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f }; // Set the viewport glViewport ( 0, 0, g_width, g_height ); // Clear the color buffer glClear ( GL_COLOR_BUFFER_BIT ); // Use the program object glUseProgram ( g_programObject ); // Load the vertex data glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices ); glEnableVertexAttribArray ( 0 ); glDrawArrays ( GL_TRIANGLES, 0, 3 ); } //********************************************************************************* // JNIEXPORT void JNICALL Java_com_jnirenderer_RendererJNI_glesResize(JNIEnv *pEnv, jobject obj, jint width, jint height) { g_width = width; g_height = height; }
#version 300 es layout(location = 0) in vec4 vPosition; void main() { gl_Position = vPosition; }
#version 300 es precision mediump float; out vec4 fragColor; void main() { fragColor = vec4(1.0, 0.0, 0.0, 1.0); }
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := JNIOpenGLES30 LOCAL_SRC_FILES := com_jnirenderer_RendererJNI.c LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv3 include $(BUILD_SHARED_LIBRARY)