一个简单的OpenGL ES 3.0 示例 (Android NDK jni)

OpenGL ES 3.0 上的一个三角形例子,网上可以下载到android skd 版(java)和 android ndk (c&c++版)

为了了解一下JNI,于是写了如下小程序。

这个例子是使用jni, java中调用c中的代码完成三角形的渲染, 其中shader代码保存在assets目录下,如下目录图:

一个简单的OpenGL ES 3.0 示例 (Android NDK jni)_第1张图片


其中,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);
	}
}

RendererJNI.java代码如下:

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

com_jnirenderer_RendererJNI.c 代码如下:

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

vs.glsl 和 fs.glsl 中的shader代码分别如下:

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

Android.mk 如下:

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)

程序运行的效果和书上给的完全一样,一个红三角形 ! ! !










你可能感兴趣的:(一个简单的OpenGL ES 3.0 示例 (Android NDK jni))