Android OpenGL ES 相关的包主要定义在
其中GLSurfaceView 为android.opengl 包中核心类:
使用过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一个可能的实现如下:
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.
public
void
setRenderer(GLSurfaceView.Renderer renderer)
GLSurfaceView.Renderer定义了一个统一图形绘制的接口,它定义了如下三个接口函数:
// 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)
如果有需要,也可以通过函数来修改GLSurfaceView一些缺省设置:
GLSurfaceView 缺省创建为RGB_565 颜色格式的Surface ,如果需要支持透明度,可以调用getHolder().setFormat(PixelFormat.TRANSLUCENT).
GLSurfaceView 的渲染模式有两种,一种是连续不断的更新屏幕,另一种为on-demand ,只有在调用requestRender() 在更新屏幕。 缺省为RENDERMODE_CONTINUOUSLY 持续刷新屏幕。