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