Android OpenGL ES 开发教程(6):GLSurfaceView

http://www.imobilebbs.com/wordpress/?p=1889

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
class GLSurfaceView extends SurfaceView
  implements SurfaceHolder.Callback, Runnable {
  public GLSurfaceView(Context context) {
  super (context);
  mHolder = getHolder();
  mHolder.addCallback( this );
  mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
  }
 
  public void setRenderer(Renderer renderer) {
  mRenderer = renderer;
  }
 
  public void surfaceCreated(SurfaceHolder holder) {
  }
 
  public void surfaceDestroyed(SurfaceHolder holder) {
  running = false ;
  try {
  thread.join();
  } catch (InterruptedException e) {
  }
  thread = null ;
  }
 
  public void surfaceChanged(SurfaceHolder holder,
  int format, int w, int h) {
  synchronized ( this ){
  mWidth = w;
  mHeight = h;
  thread = new Thread( this );
  thread.start();
  }
  }
 
  public interface Renderer {
  void EGLCreate(SurfaceHolder holder);
  void EGLDestroy();
  int Initialize( int width, int height);
  void DrawScene( int width, int height);
  }
 
  public void run() {
  synchronized ( this ) {
  mRenderer.EGLCreate(mHolder);
  mRenderer.Initialize(mWidth, mHeight);
 
  running= true ;
  while (running) {
  mRenderer.DrawScene(mWidth, mHeight);
  }
 
  mRenderer.EGLDestroy();
  }
  }
 
  private SurfaceHolder mHolder;
  private Thread thread;
  private boolean running;
  private Renderer mRenderer;
  private int mWidth;
  private int mHeight;
 
}
 
class GLRenderer implements GLSurfaceView.Renderer {
  public GLRenderer() {
  }
 
  public int Initialize( int width, int height){
  gl.glClearColor( 1 .0f, 0 .0f, 0 .0f, 0 .0f);
 
  return 1 ;
  }
 
  public void DrawScene( int width, int height){
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
 
  egl.eglSwapBuffers(eglDisplay, eglSurface);
  }
 
  public void EGLCreate(SurfaceHolder holder){
  int [] num_config = new int [ 1 ];
  EGLConfig[] configs = new EGLConfig[ 1 ];
  int [] configSpec = {
  EGL10.EGL_RED_SIZE,             8 ,
  EGL10.EGL_GREEN_SIZE,         8 ,
  EGL10.EGL_BLUE_SIZE,         8 ,
 
  EGL10.EGL_SURFACE_TYPE,     EGL10.EGL_WINDOW_BIT,
  EGL10.EGL_NONE
  };
 
  this .egl = (EGL10) EGLContext.getEGL();
 
  eglDisplay = this .egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
  this .egl.eglInitialize(eglDisplay, null );
 
  this .egl.eglChooseConfig(eglDisplay, configSpec,
  configs, 1 , num_config);
 
  eglConfig = configs[ 0 ];
  eglContext = this .egl.eglCreateContext(eglDisplay, eglConfig,
  EGL10.EGL_NO_CONTEXT, null );
 
  eglSurface = this .egl.eglCreateWindowSurface(eglDisplay,
  eglConfig, holder, null );
 
  this .egl.eglMakeCurrent(eglDisplay, eglSurface,
  eglSurface, eglContext);
 
  gl = (GL10)eglContext.getGL();
  }
 
  public void EGLDestroy(){
  if (eglSurface != null ) {
  egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,
  EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
  egl.eglDestroySurface(eglDisplay, eglSurface);
  eglSurface = null ;
  }
  if (eglContext != null ) {
  egl.eglDestroyContext(eglDisplay, eglContext);
  eglContext = null ;
  }
  if (eglDisplay != null ) {
  egl.eglTerminate(eglDisplay);
  eglDisplay = null ;
  }
  }
 
  private EGL10 egl;
  private GL10 gl;
  private EGLDisplay eglDisplay;
  private EGLConfig  eglConfig;
  private EGLContext eglContext;
  private EGLSurface eglSurface;
}

可以看到需要派生SurfaceView ,并手工创建,销毁Display,Context ,工作繁琐。

使用GLSurfaceView 内部提供了上面类似的实现,对于大部分应用只需调用一个方法来设置OpenGLView用到的GLSurfaceView.Renderer.

帮助
1
public void  setRenderer(GLSurfaceView.Renderer renderer)

GLSurfaceView.Renderer定义了一个统一图形绘制的接口,它定义了如下三个接口函数:

帮助
1
2
3
4
5
6
// Called when the surface is created or recreated.
public void onSurfaceCreated(GL10 gl, EGLConfig config)
// Called to draw the current frame.
public void onDrawFrame(GL10 gl)
// Called when the surface changed size.
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 持续刷新屏幕。

你可能感兴趣的:(java,thread,android,null,buffer,图形)