【OpenGL/ES】 第02讲 Android JNI 调用OpenGL ES 2.0
来源:互联网 发布:小红书 有钱人 知乎 编辑:程序博客网 时间:2024/04/30 12:01
如何在Android上调用C/C++程序,进而直接把你写的3D程序移植到Android上,是一个对很多人来说比较麻烦的事情,因为这要求会C++的同时还要了解Java和Android的基础知识,在某种程度上cocos2dx和unity3d正是因为在这种方面做得很优秀才脱颖而出的,没有多少人真心愿意用别人做的东西,unity3d迫使很多人放弃研究繁琐的平台细节,大幅降低游戏开发的门槛。
如果想走的远,就需要自己动手,在Android上调用c++,需要的软件环境如下:
一、Android NDK(native develop kits)
这是一个交叉编译工具,什么又是交叉编译呢,就是在一个平台编译出另一个平台可以运行的代码。从intel x86处理器平台->Android arm处理器平台。
二、cygwin - windows下的linux模拟器
安装成功后启动cygwin terminal
三、cdt - c/c++ develop tools 完成c/c++语法高亮显示
安装过程注意,安装目录和路径不要有中文和空格,避免不必要的问题出现。
以上软件作者已打包到百度云盘jni-env.zip,并附加详细安装方法,下载地址:jni-env.zip
完成环境软件安装后,按照步骤一步一步实现即可:
第一步:创建一个Android工程,Android和Java部分的知识,读者自动补齐。
第二步:在MainActivity.java中添加方法-public native String helloFromJNI()
第三步:创建jni文件夹,并创建hello.c文件
helloFromJNI的c语言命名约定:返回值(jstring) Java_包名(com_example_ndkdemo)_类名(MainActivity)_方法名(helloFromJNI) 参数(JNIEnv* env,jobject obj)
通过这种约定,jni就可以把c函数转成java函数,参数JNIEnv*是一个结构体指针里面存储的是函数指针和jobject是void*,注意命名必须一致不要写错。
public native String helloFromC();#include <stdio.h>#include <jni.h>#include "com_example_ndkdemo_MainActivity.h"jstring Java_com_example_ndkdemo_MainActivity_helloFromC(JNIEnv* env,jobject obj){return (*env)->NewStringUTF(env,"Hello From C");}
第四步:通过cygwin编译hello.c
创建Android.mk,注意下面的LOCAL_MODULE是生成的模块名,LOCAL_SRC_FILES是源文件名
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := Hello LOCAL_SRC_FILES := Hello.c include $(BUILD_SHARED_LIBRARY)
打开cygwin terminal,切换到源文件目录/cygdrive/f/Study/GameDevelop/Android/workspace/NdkDemo/jni
执行ndk-build命令,即可完成编译
第五步:在MainActivity加载libHello.so
static{System.loadLibrary("Hello");}
第六步:通过helloFromC完成对C函数的调用
public void click(View view){Toast.makeText(this,helloFromC(),1).show();//}
在主界面activity_main.xml添加一个按钮,响应函数设置为click
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hello" android:onClick="click"/>
第六步:运行效果如下,点击hello,弹出Hello From C
到了这一步,基本实现Android JNI对C/C++的调用。接下来就可以在C++里写一下OpenGL ES 2.0绘制一个三角形然后在Android中显示。
在ndk\android-ndk-r7b\samples\hello-gl2\src\com\android\gl2jni目录下,找到ndk自带的gles2的示例工程源码,里面包含三个.java文件:GL2JNIActivity,GL2JNIView,GL2JNILib,在ndk\android-ndk-r7b\samples\hello-gl2\jni目录找到Android.mk,gl_code.cpp
不出太大意外的情况下,按照下面的步骤一步一步实现即可,
第一步,在你的工程创建GL2JNIView.java,创建并配置EGLContext,创建Renderer
GL2JNIView mview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //mview = new MyTDView(this); mview = new GL2JNIView(this); //mview.requestFocus(); //mview.setFocusableInTouchMode(true); setContentView(mview); //setContentView(R.layout.activity_main); //init(); //EditText etUrl = (EditText)findViewById(R.id.et_url); }
private static String TAG = "GL2JNIView";public GL2JNIView(Context context){super(context);init(false,0,0);}
private void init(boolean translucent,int depth,int stencil){//创建EGLContextif(translucent)this.getHolder().setFormat(PixelFormat.TRANSLUCENT);//设置Context的Factory,只需派生一下GLSurfaceView.EGLContextFactorysetEGLContextFactory(new ContextFactory());//选择EGLContext的配置setEGLConfigChooser(new ConfigChooser(5,6,5,0,depth,stencil));//设置渲染器setRenderer(new Renderer());}
第二步:实现内部类ContextFactory
private static class ContextFactory implements GLSurfaceView.EGLContextFactory{private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;public EGLContext createContext(EGL10 egl,EGLDisplay display,EGLConfig eglConfig){int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION,2,EGL10.EGL_NONE};EGLContext context = egl.eglCreateContext(display,eglConfig,EGL10.EGL_NO_CONTEXT,attrib_list);return context;}public void destroyContext(EGL10 egl,EGLDisplay display,EGLContext context){egl.eglDestroyContext(display, context);}}
第三步:实现EGLContext的配置选择内部类ConfigChooser
private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser{ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { mRedSize = r; mGreenSize = g; mBlueSize = b; mAlphaSize = a; mDepthSize = depth; mStencilSize = stencil; } private static int EGL_OPENGL_ES2_BIT = 4; private static int[] s_configAttribs2 = { EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; public EGLConfig chooseConfig(EGL10 egl,EGLDisplay display) { int[] num_config = new int[1]; egl.eglChooseConfig(display,s_configAttribs2,null,0,num_config); int numConfigs = num_config[0]; if (numConfigs <= 0) { throw new IllegalArgumentException("No configs match configSpec"); } /* Allocate then read the array of minimally matching EGL configs */ EGLConfig[] configs = new EGLConfig[numConfigs]; egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); return chooseConfig(egl,display,configs); } public EGLConfig chooseConfig(EGL10 egl,EGLDisplay display, EGLConfig[] configs) { for(EGLConfig config:configs){ int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0); int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0); // We need at least mDepthSize and mStencilSize bits if (d < mDepthSize || s < mStencilSize) continue; // We want an *exact* match for red/green/blue/alpha int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0); int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0); int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0); int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0); if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) return config; } return null; } private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) { if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { return mValue[0]; } return defaultValue; } // Subclasses can adjust these values: protected int mRedSize; protected int mGreenSize; protected int mBlueSize; protected int mAlphaSize; protected int mDepthSize; protected int mStencilSize; private int[] mValue = new int[1];}
第四步:实现Renderer
private static class Renderer implements GLSurfaceView.Renderer { public void onDrawFrame(GL10 gl) { GL2JNILib.step(); } public void onSurfaceChanged(GL10 gl, int width, int height) { GL2JNILib.init(width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { // Do nothing. } }
第五步:实现Renderer所用到的GL2JNILib,声明step,init方法
public class GL2JNILib {static{System.loadLibrary("gl2jni");} /** * @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();}
第六步:编写Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := gl2jni LOCAL_SRC_FILES := gl_code.cpp LOCAL_LDLIBS := -llog -lGLESv2 include $(BUILD_SHARED_LIBRARY)
第七步:使用cygwin编译jni目录下的gl_code.cpp,Android.mk,注意修改一下下面函数的包名为你的工程包名
extern "C" { JNIEXPORT void JNICALL Java_com_example_ndkdemo_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height); JNIEXPORT void JNICALL Java_com_example_ndkdemo_GL2JNILib_step(JNIEnv * env, jobject obj);};JNIEXPORT void JNICALL Java_com_example_ndkdemo_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height){ setupGraphics(width, height);}JNIEXPORT void JNICALL Java_com_example_ndkdemo_GL2JNILib_step(JNIEnv * env, jobject obj){ renderFrame();}
最终结果,在一个配置很渣的Coolpad上:
如果本文给你带来实际的学习价值,请尊重作者的劳动成果
- 【OpenGL/ES】 第02讲 Android JNI 调用OpenGL ES 2.0
- 【OpenGL/ES】 第03讲 OpenGL/ES错误检测
- android OpenGL ES 2.0
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
- Android OpenGL ES 2.0画立方体JNI实现
- Android OpenGL ES 2.0画立方体JNI实现
- ndk jni Android OpenGL es 2.0 课程分享
- OPENGL|ES 第一天
- OpenGL ES 2.0 for Android
- Android OpenGL ES 2.0绘图:搭建OpenGL ES环境
- android opengl es 源码
- Android NDK opengl ES
- android的opengl es
- android opengl es--立方体
- Android OpenGL ES
- android opengl es
- 数据库Sharding的基本思想和切分策略
- springMVC注解前台像后台传值的两种方式
- gflags调试访问越界
- 从MVC和三层架构说到ssh整合开发
- iOS视频处理之---视频截取及添加背景音乐
- 【OpenGL/ES】 第02讲 Android JNI 调用OpenGL ES 2.0
- cocos2dx3.3-从windows8的vs12移植到mac的xcode7.2
- 盘点iOS开发者必看的105个全球最佳博客
- 常见Oracle HINT用法
- MonkeyRunner
- BZOJ3196 3223 3224 二逼平衡树,文艺平衡树,普通平衡树
- 深入浅出外观模式(二):外观模式应用实例
- Enabling Page Heap Verification
- 记录,第一天开博