OpenGL ES2 学习教程1——Android入口 - 游戏生活
本教程适用于学习opengles,采用c++语言。基于Android平台。源码可以从这里获取。
创建工程
可以使用android-studio,eclipse去创建一个工程,这里我使用命令行(Android的环境配置略)。
# create android projectmkdir GlesTutorialcd GlesTutorialandroid create project --target android-19 --name GlesTutorial --path ./ --package com.richard.glestutorial --activity AppActivity# jni portmkdir jni# core c++ codemkdir core
在项目的根目录下创建一个jni目录,用来放jni相关的文件,core为我们以后主要使用的编程目录,将只存放c++代码。
这里run没问题就继续。
创建SurfaceView
我们不再使用sdk中的api去创建view,而是利用opengl-es来创建我们的view。android里可以用到GLSurfaceView,这是给Opengl专用的。
在AppActivity中采用我们自己的view,并将一些生命周期状态发送给我们自己的View:
package com.richard.glestutorial;import android.app.Activity;import android.os.Bundle;public class AppActivity extends Activity{ protected AppSurfaceView mView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mView = new AppSurfaceView(getApplication()); setContentView(mView); } @Override protected void onPause() { super.onPause(); mView.onPause(); } @Override protected void onResume() { super.onResume(); mView.onResume(); } @Override protected void onDestroy() { super.onDestroy(); }}
创建AppSurfaceView.java 继承GLSurfaceView:
package com.richard.glestutorial;import android.content.Context;import android.opengl.GLSurfaceView;public class AppSurfaceView extends GLSurfaceView { protected GLRenderer mRender; public AppSurfaceView(Context context) { super(context); setEGLContextClientVersion(2); // set OpenGLES version mRender = new GLRenderer(); // SurfaceView 需要设置一个渲染对象,待会自己实现一个SurfaceView.Renderer setRenderer(mRender); } @Override public void onPause() { super.onPause(); mRender.handleOnPause(); } @Override public void onResume() { super.onResume(); mRender.handleOnResume(); }}
GLRendder.java:
package com.richard.glestutorial;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;import android.opengl.GLSurfaceView.Renderer;import android.util.Log;public class GLRenderer implements Renderer { static { System.loadLibrary("gltutorial"); // 一起来就加载c++库文件,待会来指定这个库 } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLRenderer.nativeInit(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLRenderer.nativeOnReSize(width, height); } @Override public void onDrawFrame(GL10 gl) { GLRenderer.nativeUpdate(); } public void handleOnPause() { GLRenderer.nativeOnPause(); } public void handleOnResume() { Log.v("GLES Tutorial", "nativeOnResume"); GLRenderer.nativeOnResume(); } // ------------------------------------------------------------ // Native Method private static native void nativeInit(); private static native void nativeOnReSize(int width, int height); private static native void nativeUpdate(); private static native void nativeOnPause(); private static native void nativeOnResume();}
这里设置了GLRenderer中声明了5个native方法,分别为:初始化;重绘制时设置view大小;每帧更新;暂停(退出前台);继续(回到前台)。将这些必备的状态通知给C++。以便我们进行绘制。
编写库
好了,接下来先编写Android.mk,用以生成libgltutorial.so这个库。在jni目录下新建Android.mk:
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := gltutorialLOCAL_LDLIBS := -llog -lGLESv2LOCAL_CFLAGS := -WerrorLOCAL_CPPFLAGS := -std=c++11include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE 指定了这个库的名字并添加了log库,opengl-es2这两个库给c++使用。LOCAL_CFLAGS是c/c++编译选项,Werror是警告也作为错误信息在编译时给出。BUILD_SHARED_LIBRARY是指定编译为动态库。
native实现
库是有了,还没有添加内容,这里要将GLRenderer中的native的实现以及我们自己定义的C++代码全部作为库。
先实现native方法:在bin下找到java源码build后的位置classes,运行javah生成native头文件: com_richard_glestutorial_GLRenderer.h。
cd bin/classesjavah -classpath ~/dev/android/android-sdk-macosx/platforms/android-19/android.jar:. com.richard.glestutorial.GLRenderermv com_richard_glestutorial_GLRenderer.h ../../jni/
编写实现代码:com_richard_glestutorial_GLRenderer.cpp:这里为了以后使用方便,新建一个Director在根目录的core/中。
#include "com_richard_glestutorial_GLRenderer.h"#include "../core/Director.h"JNIEXPORT void JNICALL Java_com_richard_glestutorial_GLRenderer_nativeInit (JNIEnv *env, jclass thiz){ Director::getInstance();}JNIEXPORT void JNICALL Java_com_richard_glestutorial_GLRenderer_nativeOnReSize (JNIEnv *env, jclass thiz, jint width, jint height){ Director::getInstance()->setFrameSize(width, height);}JNIEXPORT void JNICALL Java_com_richard_glestutorial_GLRenderer_nativeUpdate (JNIEnv *env, jclass thiz){ Director::getInstance()->mainLoop();}JNIEXPORT void JNICALL Java_com_richard_glestutorial_GLRenderer_nativeOnPause (JNIEnv *env, jclass thiz){ Director::getInstance()->onEnterBackground();}JNIEXPORT void JNICALL Java_com_richard_glestutorial_GLRenderer_nativeOnResume (JNIEnv *env, jclass thiz){ Director::getInstance()->onEnterForeground();}
Director的定义如下:
Director.h:
#ifndef _DRECTOR_H__#define _DRECTOR_H__class Director{public: static Director* getInstance(); void init(); void setFrameSize(float width, float height); void mainLoop(); void onEnterForeground(); void onEnterBackground();private: Director(); ~Director(); float _fFrameWidth; float _fFrameHeight;};
其实现可以添加一些log。可以用于查看。
最后要在Android.mk中指定所有的c++代码:
LOCAL_SRC_FILES := \com_richard_glestutorial_GLRenderer.cpp \../core/Director.cpp LOCAL_C_INCLUDES := \$(LOCAL_PATH)
Run
最后运行,我们就可以看到一个空白的view的界面。以后我们就可以在上面写界面了。