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

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一个可能的实现如下:

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

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

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

1public void  setRenderer(GLSurfaceView.Renderer renderer)

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值