TextureView
在TextureView裏也可以使用OpenGL來繪制. 其原理其實很簡單, 就是把TextureView裏面的SurfaceTexture傳給OpenGL, 然後於此SurfaceTexture進行繪制. 畫完後再使用 mEgl.eglSwapBuffers(mEglDisplay, mEglSurface) 將surfaceTexture送回TextureView中顯示
TextureView沒有自己的執行緒, 所以需要在onSurfaceTextureAvailable中啟動Rendder執行緒. 而onSurfaceTextureUpdate, 每秒會更新約60次左右
public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener{
TextureView textureView;
Thread thread;
int count=0;
long t1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView=(TextureView)findViewById(R.id.textureView);
textureView.setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
Log.d("Thomas", "available");
thread=new MyRenderer(this, surfaceTexture);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
Log.d("Thomas", "Changed");
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
count++;
long now = System.currentTimeMillis();
if (now - t1 >= 1000) {
t1 = now;
Log.d("Thomas", Thread.currentThread().getName() + " : " + count);
count = 0;
}
}
}
Renderer
如同第二章, 需要一個Renderer. 此Renderer需要手動撰寫獨立的執行緒, 並初始化OpenGL. initGL() 的目的是將TextureView裏的SurfaceTexture與OpenGL的mEglSurface進行連結, 然後在於surfaceTexture開始繪制三角型. 當surfaceTexture繪制完成後, 使用 mEgl.eglSwapBuffers(mEglDisplay, mEglSurface) 將surfaceTexture送到mEglDisplay, 如此TextureView就可以看到圖型了
請注意, 需要初始化initGL()後, 才可以產生Triangle物件, 並開始繪圖onDraw(). 迴圈裏若沒有使用Thread.sleep(10), 則會高速執行, 每秒約執行800多次. 但實際送到TextureView的每秒只有60次, 所以可以睡一下節省電量.
public class MyRenderer extends Thread{
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLConfig mEglConfig;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
Context context;
SurfaceTexture surfaceTexture;
Triangle triangle;
public MyRenderer(Context context, SurfaceTexture surfaceTexture){
this.context=context;
this.surfaceTexture=surfaceTexture;
start();
}
public synchronized void run(){
initGL();
triangle=new Triangle();
while(true){
triangle.onDraw();
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)){
throw new RuntimeException("Cannot swap buffers");
}
try {
Thread.sleep(10);//UI的onSurfaceTextureUpdated每秒只會更新60frame左右, 所以睡一下,較省電
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void initGL() {
mEgl = (EGL10) EGLContext.getEGL();
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int versions[] = new int[2];
mEgl.eglInitialize(mEglDisplay, versions);
int configsCount[] = new int[1];
EGLConfig configs[] = new EGLConfig[1];
int configSpec[] = new int[]{
EGL10.EGL_RENDERABLE_TYPE,
EGL14.EGL_OPENGL_ES2_BIT,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 0,
EGL10.EGL_STENCIL_SIZE, 0,
EGL10.EGL_NONE };
mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount);
mEglConfig = configs[0];
int contextSpec[] = new int[]{
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE };
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, contextSpec);
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceTexture, null);
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
}
}
Triangle
Triangle.java及MyShaderFactory著色器與第二章一模一樣
完整程式碼下載 : OpenGL_TextureView.rar
