在上篇文章中我们说到:硬编码通过getInputSuface()获取surface实体,然后通过opengl es 的api将图像渲染至suface上就可以完成编码的方式。
本文来说一说opengl 的相关内容。
OpenGL(Open Graphics Library)定义了一个跨编程语言、跨平台编程的专业图形程序接口。可用于二维或三维图像的处理和渲染,它是一个功能强大、调用方便的底层图形库。OpenGL ES(OpenGL for Embeddled Systems)版本,是针对手机、Pad等嵌入式设备而设计的。简化和去除了OpenGL 的一些功能,相对精简。
OpenGL是跨平台的,提供了绘制渲染的流程接口,而具体渲染在哪个窗口、上下文环境的初始化等任务则交付由平台设计实现。Android系统上通过EGL的api来实现。OpenGL的运行以依赖于EGL环境的创建。EGL环境是绑定线程创建的,简单而言,在哪个线程调用EGL的创建api,该EGL环境就绑定在哪个线程上。UI主线程是没有绑定EGL环境的,所以在UI主线程上调用OpenGL ES的api是无效的(OpenGL ES的api并不会抛出java异常,UI主线程上调用OpenGL ES的api并不会有什么具体表现)。
要调用OpenGL es我们需要创建一个线程,在这个线程中初始化EGLContext,这在硬编码中这是重要的一步,但是这个过程涉及的内容较多,我们以后再说。我们先使用Android系统为我们准备的一个一键解决方案——GLSurfaceView。
GLSurfaceView
GLSurfaceView 内部帮我们创建了一个GLThread,简单而言就是一个初始化了EGLContext环境的线程。GLSurfaceView提供了setRenderer方法供我们设置一个运行在GLThread线程上的回调方法。
glSurface.setRenderer(new GLSurfaceView.Renderer() {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
@Override
public void onDrawFrame(GL10 gl) {
}
});
onSurfaceCreated会在EGL环境初始化完成后调用,时序最早。
onSurfaceChanged 随后被调用,如果之后GLSurfaceView的高宽发生了变化onSurfaceChanged也会被调用。
onDrawFrame,故名思意,在绘制每一帧时调用,时序最后,GLSurfaceView提供了两种触发绘制的方式
surface.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
surface.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
RENDERMODE_WHEN_DIRTY:手动调用模式:
surface.requestRender();
通过调用上面的方法触发onDrawFrame的回调。
RENDERMODE_CONTINUOUSLY:自动调用模式,GLThread会一直反复的调用onDrawFrame。
简单理解的话:GLThread线程会依次调用这三个Renderer回调,然后在onDrawFrame循环:
onSurfaceCreated>onSurfaceChanged>onDrawFrame>onDrawFrame>onDrawFrame>。。。
需要注意的是:setRenderMode须在setRenderer之后调用,不调用的话,默认是RENDERMODE_CONTINUOUSLY模式。
细心的朋友也许注意到了onSurfaceCreated的参数中有个GL10,GLSurfaceView默认支持Opengl es 1.0的api。现在用得比较多的是Opengl es2.0的api,通过GLES20的静态方法调用,而要在GLSufaceView中调用则需要先调用方法设置支持Opengl es 2.0:
surface.setEGLContextClientVersion(2);
官方说明需要在AndroidManifest中添加<uses-feature android:glEsVersion="0x00020000" />(用来标识本程序运行需要opengl es 2.0的api实现,绝大多数手机都支持opengl es 2.0,所以没加一般也不会引发什么问题),另外需要注意的是:该方法必须在setRenderer之前调用。
说了这么多,实际简单使用GLSurfaceView就两步
glSurface.setEGLContextClientVersion(2);
glSurface.setRenderer(...);
然后在Renderer回调中调用OpenGL ES api就可以进行绘制了,下篇文章,我们来介绍一下OpenGL绘制相关的api。