OpenGLES demo - 3. 建立Android工程
来源:互联网 发布:淘宝网评价管理在哪 编辑:程序博客网 时间:2024/06/07 03:31
原创文章,转载请注明连接 http://blog.csdn.net/hoytgm/article/details/32715655
Android主要都是Java代码,但是我们建立OpenGLES工程,主要还是调用C/C++代码,所以我们需要使用Jni(Java Native Interface)。这里代码的东西比较少,很多都是贴一些Java相关的,本人Java不太熟,所以很多地方就不解释了哈,要是有更好的代码,欢迎指正哈。
根目录下建立AndroidManifest.xml文件,内容照贴
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hoytgm" > <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="hoytgm" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application><uses-sdk android:minSdkVersion="7" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /></manifest>
然后就是Android.mk,这个是Android下面的makefile,大家应该比我懂吧
## Build #LOCAL_PATH := $(call my-dir)# Build apkinclude $(CLEAR_VARS)LOCAL_MODULE_PATH := $(LOCAL_PATH)/bin/LOCAL_PACKAGE_NAME := hoytgmLOCAL_SRC_FILES := \$(call all-subdir-java-files)LOCAL_JNI_SHARED_LIBRARIES := \libhoytgmLOCAL_MODULE_TAGS := eng optionalinclude $(BUILD_PACKAGE)# Build native shared objectinclude $(CLEAR_VARS)LOCAL_MODULE := libhoytgmLOCAL_SRC_FILES := \jni/jniapi.cpp \./main.cpp LOCAL_C_INCLUDES := \./LOCAL_SHARED_LIBRARIES := \liblog \libEGL \libGLESv2 \libandroid LOCAL_CFLAGS := \-Wall \-DANDROIDLOCAL_MODULE_TAGS := eng optionalLOCAL_PRELINK_MODULE := falseinclude $(BUILD_SHARED_LIBRARY)
建立三个文件夹和相应的文件,参照我的层次哈,打括号是指目录
(jni) -> jniapi.cpp
(src) -> (com)--> (hoytgm) -> hoytgm.java
(res) -> (drawable)
(res) -> (layout) -> main.xml
(res) -> (values) -> strings.xml
然后是main.xml文件的内容
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ><SurfaceView android:id="@+id/surfaceview" android:layout_width="fill_parent" android:layout_height="wrap_content" /><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#ffffffff" android:textSize="60dp" /></RelativeLayout>
和strings.xml的内容
<?xml version="1.0" encoding="utf-8"?><resources><string name="app_name">hoytgm</string></resources>
package com.hoytgm;import android.app.Activity;import android.os.Bundle;import android.widget.Toast;import android.view.Surface;import android.view.SurfaceView;import android.view.SurfaceHolder;import android.view.View;import android.view.View.OnClickListener;import android.util.Log;
然后实现一个SurfaceHolder的类,作为主要的activity
public class hoytgm extends Activity implements SurfaceHolder.Callback {}
在类里面添加一个成员用于打印标志
private static String TAG = "### hoytgm: ";
重载create函数
@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.i(TAG, "onCreate()");setContentView(R.layout.main);SurfaceView surfaceView = (SurfaceView)findViewById(R.id.surfaceview);surfaceView.getHolder().addCallback(this);surfaceView.setOnClickListener(new OnClickListener() {public void onClick(View view) {}});}
重载几个状态的函数
@Overrideprotected void onStart() {super.onStart();Log.i(TAG, "onStart()");nativeOnStart();}@Overrideprotected void onResume() {super.onResume();Log.i(TAG, "onResume()");nativeOnResume();}@Overrideprotected void onPause() {super.onPause();Log.i(TAG, "onPause()");nativeOnPause();}@Overrideprotected void onStop() {super.onStop();Log.i(TAG, "onStop()");nativeOnStop();}public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.i(TAG, "surfaceChanged()");nativeSetSurface(holder.getSurface());}public void surfaceCreated(SurfaceHolder holder) { Log.i(TAG, "surfaceCreated()");}public void surfaceDestroyed(SurfaceHolder holder) {nativeSetSurface(null);}
这里大家会发现一些native*()的函数,这些就是需要jniapi.cpp去实现的函数,这里把这些函数的声明也加到我们的这个类里面,并加载这个库
public static native void nativeOnStart();public static native void nativeOnResume();public static native void nativeOnPause();public static native void nativeOnStop();public static native void nativeSetSurface(Surface surface);static {System.loadLibrary("hoytgm");}
好了,到这里,我们的hoytgm.java就完成了,java相关的代码也结束了,可以开始写jniapi.cpp文件了,先一次性贴出整个文件的代码吧,因为这里就是按照之前的路径和jni的格式把hoytgm.java里面的几个native开头的函数实现了,然后自己创建一个线程用于做Opengl es相关的渲染工作。
/* */#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#include <jni.h>#include <android/log.h>#include <android/native_window.h>#include <android/native_window_jni.h>#include <nativehelper/JNIHelp.h>#include <nativehelper/jni.h>#include <EGL/egl.h>#include <GLES2/gl2.h>#undef LOG_TAG#define LOG_TAG "### hoytgm:"#define MAX_SIZE 1024#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)ANativeWindow* navWindow = 0;EGLDisplay eglDisplay = 0;EGLContext eglContext = 0;EGLSurface eglSurface = 0;pthread_t mainThreadId = 0;extern bool Render();extern void fini();extern bool init();enum{KEYCODE_BACK = 4};enum RenderMessage { MSG_NONE = 0, MSG_WINDOW_SET, MSG_RENDER_LOOP_EXIT,};RenderMessage rendermsg;void destroy(){ LOG_I("destroy()"); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(eglDisplay, eglContext); eglDestroySurface(eglDisplay, eglSurface); eglTerminate(eglDisplay); eglDisplay = EGL_NO_DISPLAY; eglSurface = EGL_NO_SURFACE; eglContext = EGL_NO_CONTEXT; }void renderLoop() { bool done = false; LOG_I("renderLoop()"); static unsigned int framecount = 0; while(!done) { if(framecount < 1) { LOG_I("no render occurs, sleep 500 ms"); usleep(500); } switch(rendermsg) { case MSG_WINDOW_SET: init(); break; case MSG_RENDER_LOOP_EXIT: done = true; fini(); destroy(); break; default: break; } rendermsg = MSG_NONE; if(eglDisplay) { done = Render(); framecount++; if(!eglSwapBuffers(eglDisplay, eglSurface)) { if(framecount % 60 == 0) { LOG_E("eglSwapBuffers() returned error: %d", eglGetError()); } } } }}void* threadCallback(void* ){ renderLoop(); LOG_I("thread exit 0"); pthread_exit(0); return 0;}extern "C" {JNIEXPORT void JNICALL Java_com_hoytgm_hoytgm_nativeOnStart(JNIEnv* jenv, jobject obj){LOG_I("nativeOnStart()"); return;}JNIEXPORT void JNICALL Java_com_hoytgm_hoytgm_nativeOnResume(JNIEnv* jenv, jobject obj){LOG_I("nativeOnResume()"); pthread_create(&mainThreadId, 0, threadCallback, 0); LOG_I("thread id: %ld", mainThreadId); return;}JNIEXPORT void JNICALL Java_com_hoytgm_hoytgm_nativeOnPause(JNIEnv* jenv, jobject obj){LOG_I("nativeOnPause()"); rendermsg = MSG_RENDER_LOOP_EXIT; return;}JNIEXPORT void JNICALL Java_com_hoytgm_hoytgm_nativeOnStop(JNIEnv* jenv, jobject obj){LOG_I("nativeOnStop()"); rendermsg = MSG_RENDER_LOOP_EXIT; return;}JNIEXPORT void JNICALL Java_com_hoytgm_hoytgm_nativeSetSurface(JNIEnv* jenv, jobject obj, jobject surface){ if(surface != 0) { navWindow = ANativeWindow_fromSurface(jenv, surface); LOG_I("Got window %p", navWindow); rendermsg = MSG_WINDOW_SET; } else { LOG_I("Releasing window"); ANativeWindow_release(navWindow); }}} // extern "C"
到这里了,差不多就可以工作了吧?当然不行。。。不信你去根目录(有Android.mk)下编译,保证不过~~~因为我们还缺一个main.cpp,这个文件在Android.mk里面已经写好了, 但是我们没有创建并且实现它。而且,我们后面要做的所有工作将在这个文件里面完成,上面写的所有东西,以后几乎都不会碰了。根目录下创建main.cpp文件,这个里面部分渲染工作和第一章讲的都一样,唯一不同的是创建EGL。我觉得Andriod下面创建EGL的方法更有助于我们直接的去了解EGL的参数的创建过程,IOS上面一直觉得怪怪的。。。。。。
首先,我们需要定义一个数组来决定我们需要建立一个怎么样的EGL,也就是定义RGBA的bit大小,需不需要Depth,Stencil,要不要开MSAA等等。同时还需要定义一个额外的数组来告诉显卡我们需要哪个版本。
const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLES, 0, EGL_NONE, }; EGLint attribListContext[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(egldisplay == EGL_NO_DISPLAY) { output_log("eglGetDisplay() returned error: 0x%x\n", eglGetError()); return false; } if(!eglInitialize(egldisplay, 0, 0)) { output_log("eglInitialize() returned error: 0x%x\n", eglGetError()); return false; }
我们需要知道当前的Display支持多少种配置,不出意外的话,我们刚才列出的那个属性就应该有对应的配置
/* Get how many configs does the device support */ if(!eglGetConfigs(egldisplay, NULL, 0, &num_config)) { output_log("eglGetConfigs(NULL) returned error: 0x%x\n", eglGetError()); return false; }
好了,我们现在传入刚才的属性数组,看下能得到多少个满足这个条件的配置,也就是很重要的eglChooseConfig
if(!eglChooseConfig(egldisplay, attribs, eglConfig_array, num_config, &supportConfigCount)) { output_log("eglChooseConfig() returned error: 0x%x\n", eglGetError()); return false; }
通过eglChooseConfig,我们就能得到我们支持的一个config id,用这个id,我们就能够创建一个eglcontext。eglcontext是一个非常重要的句柄,我们所需要画的任何东西,任何OpenGLES相关的操作,都需要在一个context下面才能工作。
if(!(eglcontext = eglCreateContext(egldisplay, eglConfig, 0, attribListContext))) { output_log("eglCreateContext() returned error: 0x%x\n", eglGetError()); return false; }
有了context,我们就差一个surface了,这个surface就相当于我们的backbuffer,所有画的操作和结果都是默认放在这个surface上面的
if(!(eglsurface = eglCreateWindowSurface(egldisplay, eglConfig, navWindow, 0))) { output_log("eglCreateWindowSurface() returned error: 0x%x\n", eglGetError()); return false; }
有了eglcontext和eglsurface了,我们再调用eglMakeCurrent将eglcontext设置为当前,我们就可以开始做GLES的工作了。
if(!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { output_log("eglMakeCurrent() returned error: 0x%x\n", eglGetError()); return false; }
到这里为止,我们在Android上面的工作基本就结束了。剩下的三个函数,init(), Render()和fini()都和IOS上面差不多了。有兴趣的同学可以去我的资源上面下载Android工程的源码并编译,会生成一个apk,就可以安装到虚拟机或者Android手机上面看结果。贴下代码的资源地址 http://download.csdn.net/detail/hoytgm/7532901
好了,Android工程的建立就到这里了。后面demo的代码主要都是在IOS上面实现的,用Android开发的同学们照着代码搬到Android应该没问题吧???调用都是相同的话,如果搬代码过程有什么问题,欢迎大家交流。
- OpenGLES demo - 3. 建立Android工程
- OpenGLES demo - 1. 建立IOS工程
- webrtc工程DEMO建立
- OpenGLES demo - 2. Shader
- android建立库工程
- OpenGLES demo - 5. 深度测试
- OpenGLES demo - 6. Cull Face
- OpenGLES demo - 7. Alpha Blend
- OpenGLES demo - 9. 矩阵变换
- OpenGLES demo - 11. 透视投影变换
- OpenGLES demo - 16. 蒙板 Stencil
- Maven,Gradle分别建立Spring-boot的demo工程
- android opengles---混合
- android opengles---混合
- Android OpenGLES 学习笔记
- Android Opengles 学习一
- android平台初始化opengles
- Android OpenglES 反锯齿
- android 使用Webview时候清楚缓存各种方式无效后
- PHP 开启报错提示
- 查找没有commit的事务
- 管理员克隆gitolite-admin时提示“ERROR:gitosis.app:Configuration does not exist”错误
- 使用Lucene-Spatial实现集成地理位置的全文检索
- OpenGLES demo - 3. 建立Android工程
- MyEclipse6.0.1安装离线maven插件包
- SurfaceView 典型用法
- TestNG插件与ANT
- 克鲁斯卡尔算法生成最小生成树
- baidu卫兵世界杯智能提速 打破运营商OTT"端"阻力
- 基于.NET的模板引擎 NVelocity
- test2
- 广州高校学生发起百人裸跑要求校方安装空调