您的位置:首页 > 运维架构

基于textureview编写opengl程序

2013-05-15 18:11 351 查看
与SurfaceView相比,TextureView并没有创建一个单独的Surface用来绘制,这使得它可以像一般的View一样执行一些变换操作,设置透明度等。

另外,Textureview必须在硬件加速开启的窗口中。下面的例子演示了通过TextureView来创建一个opengl程序。

基于TextureView的程序,我们需要实现TextureView.SurfaceTextureListener这个接口,首先给出Activity的代码,在该类中,我们实现了此接口:

package com.fyj.test;

import java.util.concurrent.atomic.AtomicBoolean;

import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.view.TextureView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class TextureviewtestActivity extends Activity implements TextureView.SurfaceTextureListener{

private TextureView mTextureView;
private Thread mProducerThread = null;
private GLRendererImpl mRenderer;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
mTextureView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);//隐藏虚拟按键,即navigator bar
setContentView(mTextureView);

mRenderer = new GLRendererImpl(this);
}

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
int height) {
// TODO Auto-generated method stub
mRenderer.setViewport(width, height);
mProducerThread = new GLProducerThread(surface, mRenderer, new AtomicBoolean(true));
mProducerThread.start();
}

@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
// TODO Auto-generated method stub
mProducerThread = null;
return true;
}

@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
int height) {
// TODO Auto-generated method stub
mRenderer.resize(width, height);

}

@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// TODO Auto-generated method stub

}
}


其中,在方法onSurfaceTextureAvailable中,我们开启一个OpenGL线程,在该线程中执行OpenGL的一些操作,该线程的定义如下:

package com.fyj.test;

import java.util.concurrent.atomic.AtomicBoolean;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;

import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;

public class GLProducerThread extends Thread {

private AtomicBoolean mShouldRender;
private SurfaceTexture mSurfaceTexture;
private GLRenderer mRenderer;

private EGL10 mEgl;
private EGLDisplay mEglDisplay = EGL10.EGL_NO_DISPLAY;
private EGLContext mEglContext = EGL10.EGL_NO_CONTEXT;
private EGLSurface mEglSurface = EGL10.EGL_NO_SURFACE;
private GL mGL;

private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
private static final int EGL_OPENGL_ES2_BIT = 4;

public interface GLRenderer {
public void drawFrame();
}

public GLProducerThread(SurfaceTexture surfaceTexture, GLRenderer renderer, AtomicBoolean shouldRender)
{
mSurfaceTexture = surfaceTexture;
mRenderer = renderer;
mShouldRender = shouldRender;
}

private void initGL()
{
mEgl = (EGL10)EGLContext.getEGL();

mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetdisplay failed : " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}

int []version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed : " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}

int []configAttribs = {
EGL10.EGL_BUFFER_SIZE, 32,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_NONE
};

int []numConfigs = new int[1];
EGLConfig []configs = new EGLConfig[1];
if (!mEgl.eglChooseConfig(mEglDisplay, configAttribs, configs, 1, numConfigs)) {
throw new RuntimeException("eglChooseConfig failed : " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}

int []contextAttribs = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, contextAttribs);
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], mSurfaceTexture, null);
if (mEglSurface == EGL10.EGL_NO_SURFACE || mEglContext == EGL10.EGL_NO_CONTEXT) {
int error = mEgl.eglGetError();
if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
throw new RuntimeException("eglCreateWindowSurface returned  EGL_BAD_NATIVE_WINDOW. " );
}
throw new RuntimeException("eglCreateWindowSurface failed : " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}

if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent failed : " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}

mGL = mEglContext.getGL();
}

private void destoryGL()
{
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglContext = EGL10.EGL_NO_CONTEXT;
mEglSurface = EGL10.EGL_NO_SURFACE;
}

public void run()
{
initGL();

if (mRenderer != null) {
((GLRendererImpl)mRenderer).initGL();
}

while (mShouldRender != null && mShouldRender.get() != false) {
if (mRenderer != null)
mRenderer.drawFrame();
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);

try {
sleep(5);
} catch(InterruptedException e) {

}
}

destoryGL();
}
}


在该线程中,我们定义了GLRenderer接口,该接口的实现者负责具体的OpenGL绘制代码:

package com.fyj.test;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.util.Log;

import com.fyj.test.GLProducerThread.GLRenderer;

public class GLRendererImpl implements GLRenderer {

private int mProgramObject;
private int mWidth;
private int mHeight;
private FloatBuffer mVertices;
private ShortBuffer mTexCoords;
private Context mContext;
private int mTexID;
private static String TAG = "GLRendererImpl";

private final float[] mVerticesData = { -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, -0.5f, 0.5f, 0, 0.5f, 0.5f, 0 };
private final short[] mTexCoordsData = {0, 1, 1, 1, 0, 0, 1, 0};

public GLRendererImpl(Context ctx)
{
mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertices.put(mVerticesData).position(0);

mTexCoords = ByteBuffer.allocateDirect(mTexCoordsData.length * 2)
.order(ByteOrder.nativeOrder()).asShortBuffer();
mTexCoords.put(mTexCoordsData).position(0);

mContext = ctx;

}

public void setViewport(int width, int height)
{
mWidth = width;
mHeight = height;
}

public void initGL()
{
comipleAndLinkProgram();

loadTexture();

GLES20.glClearColor(0,  0, 0, 0);
}

public void resize(int width, int height)
{
mWidth = width;
mHeight = height;

}

@Override
public void drawFrame() {
// TODO Auto-generated method stub
GLES20.glViewport(0, 0, mWidth, mHeight);

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

GLES20.glUseProgram(mProgramObject);

GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices);
GLES20.glEnableVertexAttribArray(0);
GLES20.glVertexAttribPointer(1, 2, GLES20.GL_SHORT, false, 0, mTexCoords);
GLES20.glEnableVertexAttribArray(1);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID);
int loc = GLES20.glGetUniformLocation(mProgramObject, "u_Texture");
GLES20.glUniform1f(loc, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

Log.i("GLRendererImpl", "drawing..." + mWidth);
}

private void loadTexture() {
Bitmap b = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher);
if (b != null) {
int []texID = new int[1];
GLES20.glGenTextures(1, texID, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID[0]);
mTexID = texID[0];

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_REPEAT);

GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, b, 0);
b.recycle();
}
}

private int loadShader(int shaderType, String shaderSource) {
int shader;
int[] compiled = new int[1];

// Create the shader object
shader = GLES20.glCreateShader(shaderType);

if (shader == 0)
return 0;

// Load the shader source
GLES20.glShaderSource(shader, shaderSource);

// Compile the shader
GLES20.glCompileShader(shader);

// Check the compile status
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);

if (compiled[0] == 0) {
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
return 0;
}
return shader;
}

private void comipleAndLinkProgram() {
String vShaderStr = "attribute vec4 a_position;    \n"
+"attribute vec2 a_texCoords; \n"
+"varying vec2 v_texCoords; \n"
+ "void main()                  \n"
+ "{                            \n"
+ "   gl_Position = a_position;  \n"
+"    v_texCoords = a_texCoords; \n"
+ "}                            \n";

String fShaderStr = "precision mediump float;					  \n"
+"uniform sampler2D u_Texture; \n"
+"varying vec2 v_texCoords; \n"
+ "void main()                                  \n"
+ "{                                            \n"
+ "  gl_FragColor = texture2D(u_Texture, v_texCoords) ;\n"
+ "}                                            \n";

int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];

// Load the vertex/fragment shaders
vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr);
fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr);

// Create the program object
programObject = GLES20.glCreateProgram();

if (programObject == 0)
return ;

GLES20.glAttachShader(programObject, vertexShader);
GLES20.glAttachShader(programObject, fragmentShader);

// Bind vPosition to attribute 0
GLES20.glBindAttribLocation(programObject, 0, "a_position");
GLES20.glBindAttribLocation(programObject, 1, "a_texCoords");

// Link the program
GLES20.glLinkProgram(programObject);

// Check the link status
GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);

if (linked[0] == 0) {
Log.e(TAG, "Error linking program:");
Log.e(TAG, GLES20.glGetProgramInfoLog(programObject));
GLES20.glDeleteProgram(programObject);
return  ;
}

mProgramObject = programObject;
}
}


需要注意的是,所有EGL及GL相关的操作必须置于GLThread线程中进行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: