Android OpenGL ES 相关的包主要定义在
- javax.microedition.khronos.opengles GL 绘图指令
- javax.microedition.khronos.egl EGL 管理Display, surface等
- android.opengl Android GL辅助类,连接OpenGL 与Android View,Activity
- javax.nio Buffer类
其中GLSurfaceView 为android.opengl 包中核心类:
- 起到连接OpenGL ES与Android 的View层次结构之间的桥梁作用。
- 使得Open GL ES库适应于Anndroid系统的Activity生命周期。
- 使得选择合适的Frame buffer像素格式变得容易。
- 创建和管理单独绘图线程以达到平滑动画效果。
- 提供了方便使用的调试工具来跟踪OpenGL ES函数调用以帮助检查错误。
使用过Java ME ,JSR 239 开发过OpenGL ES可以看到 Android 包javax.microedition.khronos.egl ,javax.microedition.khronos.opengles 和JSR239 基本一致,因此理论上不使用android.opengl 包中的类也可以开发Android上OpenGL ES应用,但此时就需要自己使用EGL来管理Display,Context, Surfaces 的创建,释放,捆绑,可以参见Android OpenGL ES 开发教程(5):关于EGL 。
使用EGL 实现GLSurfaceView一个可能的实现如下:
1 | class GLSurfaceView extends SurfaceView |
2 | implements SurfaceHolder.Callback, Runnable { |
3 | public GLSurfaceView(Context context) { |
6 | mHolder.addCallback( this ); |
7 | mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU); |
10 | public void setRenderer(Renderer renderer) { |
14 | public void surfaceCreated(SurfaceHolder holder) { |
17 | public void surfaceDestroyed(SurfaceHolder holder) { |
21 | } catch (InterruptedException e) { |
26 | public void surfaceChanged(SurfaceHolder holder, |
27 | int format, int w, int h) { |
31 | thread = new Thread( this ); |
36 | public interface Renderer { |
37 | void EGLCreate(SurfaceHolder holder); |
39 | int Initialize( int width, int height); |
40 | void DrawScene( int width, int height); |
45 | mRenderer.EGLCreate(mHolder); |
46 | mRenderer.Initialize(mWidth, mHeight); |
50 | mRenderer.DrawScene(mWidth, mHeight); |
53 | mRenderer.EGLDestroy(); |
57 | private SurfaceHolder mHolder; |
58 | private Thread thread; |
59 | private boolean running; |
60 | private Renderer mRenderer; |
66 | class GLRenderer implements GLSurfaceView.Renderer { |
70 | public int Initialize( int width, int height){ |
71 | gl.glClearColor( 1 .0f, 0 .0f, 0 .0f, 0 .0f); |
76 | public void DrawScene( int width, int height){ |
77 | gl.glClear(GL10.GL_COLOR_BUFFER_BIT); |
79 | egl.eglSwapBuffers(eglDisplay, eglSurface); |
82 | public void EGLCreate(SurfaceHolder holder){ |
83 | int [] num_config = new int [ 1 ]; |
84 | EGLConfig[] configs = new EGLConfig[ 1 ]; |
86 | EGL10.EGL_RED_SIZE, 8 , |
87 | EGL10.EGL_GREEN_SIZE, 8 , |
88 | EGL10.EGL_BLUE_SIZE, 8 , |
90 | EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, |
94 | this .egl = (EGL10) EGLContext.getEGL(); |
96 | eglDisplay = this .egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); |
97 | this .egl.eglInitialize(eglDisplay, null ); |
99 | this .egl.eglChooseConfig(eglDisplay, configSpec, |
100 | configs, 1 , num_config); |
102 | eglConfig = configs[ 0 ]; |
103 | eglContext = this .egl.eglCreateContext(eglDisplay, eglConfig, |
104 | EGL10.EGL_NO_CONTEXT, null ); |
106 | eglSurface = this .egl.eglCreateWindowSurface(eglDisplay, |
107 | eglConfig, holder, null ); |
109 | this .egl.eglMakeCurrent(eglDisplay, eglSurface, |
110 | eglSurface, eglContext); |
112 | gl = (GL10)eglContext.getGL(); |
115 | public void EGLDestroy(){ |
116 | if (eglSurface != null ) { |
117 | egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, |
118 | EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); |
119 | egl.eglDestroySurface(eglDisplay, eglSurface); |
122 | if (eglContext != null ) { |
123 | egl.eglDestroyContext(eglDisplay, eglContext); |
126 | if (eglDisplay != null ) { |
127 | egl.eglTerminate(eglDisplay); |
134 | private EGLDisplay eglDisplay; |
135 | private EGLConfig eglConfig; |
136 | private EGLContext eglContext; |
137 | private EGLSurface eglSurface; |
可以看到需要派生SurfaceView ,并手工创建,销毁Display,Context ,工作繁琐。
使用GLSurfaceView 内部提供了上面类似的实现,对于大部分应用只需调用一个方法来设置OpenGLView用到的GLSurfaceView.Renderer.
1 | public void setRenderer(GLSurfaceView.Renderer renderer) |
GLSurfaceView.Renderer定义了一个统一图形绘制的接口,它定义了如下三个接口函数:
1 | // Called when the surface is created or recreated. |
2 | public void onSurfaceCreated(GL10 gl, EGLConfig config) |
3 | // Called to draw the current frame. |
4 | public void onDrawFrame(GL10 gl) |
5 | // Called when the surface changed size. |
6 | public void onSurfaceChanged(GL10 gl, int width, int height) |
- onSurfaceCreated : 在这个方法中主要用来设置一些绘制时不常变化的参数,比如:背景色,是否打开 z-buffer等。
- onDrawFrame: 定义实际的绘图操作。
- onSurfaceChanged: 如果设备支持屏幕横向和纵向切换,这个方法将发生在横向<->纵向互换时。此时可以重新设置绘制的纵横比率。
如果有需要,也可以通过函数来修改GLSurfaceView一些缺省设置:
- setDebugFlags(int) 设置Debug标志。
- setEGLConfigChooser (boolean) 选择一个Config接近16bitRGB颜色模式,可以打开或关闭深度(Depth)Buffer ,缺省为RGB_565 并打开至少有16bit 的 depth Buffer.
- setEGLConfigChooser(EGLConfigChooser) 选择自定义EGLConfigChooser。
- setEGLConfigChooser(int, int, int, int, int, int) 指定red ,green, blue, alpha, depth ,stencil 支持的位数,缺省为RGB_565 ,16 bit depth buffer.
GLSurfaceView 缺省创建为RGB_565 颜色格式的Surface ,如果需要支持透明度,可以调用getHolder().setFormat(PixelFormat.TRANSLUCENT).
GLSurfaceView 的渲染模式有两种,一种是连续不断的更新屏幕,另一种为on-demand ,只有在调用requestRender() 在更新屏幕。 缺省为RENDERMODE_CONTINUOUSLY 持续刷新屏幕。