package com.example.datalibrary.deptrum.openglhelper;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLES20;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
/**
*
*/
public class YUVRendThread extends BaseOpenglRenderThread {
private GLFrameRenderer glFrameRenderer;
public YUVRendThread(String name, SurfaceView mSurfaceView) {
super(name, mSurfaceView);
tAG = YUVRendThread.class.getSimpleName();
glFrameRenderer = new GLFrameRenderer();
mSurfaceView.getHolder().addCallback(glFrameRenderer);
glFrameRenderer.setResolution(640, 480);
glFrameRenderer.setDisplayOrientation(0);
glFrameRenderer.displayMirror(false);
glFrameRenderer.creatBuffer(640, 480);
}
@Override
protected void creatProgram() {
if (glFrameRenderer != null) {
glFrameRenderer.creatProgram();
}
}
@Override
protected void draw() {
if (glFrameRenderer != null) {
glFrameRenderer.onDrawFrame();
}
}
public void update(byte[] yuv420p) {
if (glFrameRenderer != null) {
glFrameRenderer.update(yuv420p);
notifyDraw();
}
}
public static class GLProgram {
private static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n"
+ "attribute vec4 vPosition;\n"
+ "attribute vec2 a_texCoord;\n"
+ "varying vec2 tc;\n"
+ "void main() {\n"
+ "gl_Position = uMVPMatrix * vPosition;\n"
+ "tc = a_texCoord;\n"
+ "}\n";
private static final String FRAGMENT_SHADER =
"precision mediump float;\n"
+ "uniform sampler2D tex_y;\n"
+ "uniform sampler2D tex_u;\n"
+ "uniform sampler2D tex_v;\n"
+ "varying vec2 tc;\n"
+ "void main() {\n"
+ "vec4 c = vec4((texture2D(tex_y, tc).r - 16./255.) * 1.164);\n"
+ "vec4 U = vec4(texture2D(tex_u, tc).r - 128./255.);\n"
+ "vec4 V = vec4(texture2D(tex_v, tc).r - 128./255.);\n"
+ "c += V * vec4(1.596, -0.813, 0, 0);\n"
+ "c += U * vec4(0, -0.392, 2.017, 0);\n"
+ "c.a = 1.0;\n"
+ "gl_FragColor = c;\n"
+ "}\n";
private float[] mViewMatrix = new float[16];
private int mVPMatrixHandle = -1;
static float[] s0Matrix = {
1.0f, 0.0f, 0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s0MirrorMatrix = {
-1.0f, 0.0f, 0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s90Matrix = {
0.0f, -1.0f, 0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s90MirrorMatrix = {
0.0f, -1.0f, 0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s180Matrix = {
-1.0f, 0.0f, 0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s180MirrorMatrix = {
1.0f, 0.0f, 0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s270Matrix = {
0.0f, 1.0f, 0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] s270MirrorMatrix = {
0.0f, 1.0f, 0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static float[] squareVertices = {
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
}; /*fullscreen*/
static float[] squareVertices1 = {
-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f,
}; /*left-top*/
static float[] squareVertices2 = {
0.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
}; /*right-bottom*/
static float[] squareVertices3 = {
-1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
}; /*left-bottom*/
static float[] squareVertices4 = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
}; /*right-top*/
private static float[] coordVertices = {
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
}; /*whole-texture*/
public final int mWinPosition;
private int mGLProgram;
private int mGLTextureI;
private int mGLTextureII;
private int mGLTextureIII;
private int mGLIndexI;
private int mGLIndexII;
private int mGLTIndexIII;
private float[] mGLVertices;
private int mPositionHandle = -1;
private int mCoordHandle = -1;
private int mYhandle = -1;
private int mUhandle = -1;
private int mVhandle = -1;
private int mYtid = -1;
private int mUtid = -1;
private int mVtid = -1;
private ByteBuffer mVerticeBuffer;
private ByteBuffer mCoordBuffer;
private int mVideoWidth = -1;
private int mVideoHeight = -1;
private boolean isProgBuilt = false;
/**
* position can only be 0~4:
* fullscreen => 0
* left-top => 1
* right-top => 2
* left-bottom => 3
* right-bottom => 4
*/
public GLProgram(int position) {
if (position < 0 || position > 4) {
throw new RuntimeException("Index can only be 0 to 4");
}
mWinPosition = position;
setup();
}
/**
* prepared for later use
*/
private void setup() {
switch (mWinPosition) {
case 1:
mGLVertices = squareVertices1;
mGLTextureI = GLES20.GL_TEXTURE0;
mGLTextureII = GLES20.GL_TEXTURE1;
mGLTextureIII = GLES20.GL_TEXTURE2;
mGLIndexI = 0;
mGLIndexII = 1;
mGLTIndexIII = 2;
break;
case 2:
mGLVertices = squareVertices2;
mGLTextureI = GLES20.GL_TEXTURE3;
mGLTextureII = GLES20.GL_TEXTURE4;
mGLTextureIII = GLES20.GL_TEXTURE5;
mGLIndexI = 3;
mGLIndexII = 4;
mGLTIndexIII = 5;
break;
case 3:
mGLVertices = squareVertices3;
mGLTextureI = GLES20.GL_TEXTURE6;
mGLTextureII = GLES20.GL_TEXTURE7;
mGLTextureIII = GLES20.GL_TEXTURE8;
mGLIndexI = 6;
mGLIndexII = 7;
mGLTIndexIII = 8;
break;
case 4:
mGLVertices = squareVertices4;
mGLTextureI = GLES20.GL_TEXTURE9;
mGLTextureII = GLES20.GL_TEXTURE10;
mGLTextureIII = GLES20.GL_TEXTURE11;
mGLIndexI = 9;
mGLIndexII = 10;
mGLTIndexIII = 11;
break;
case 0:
default:
mGLVertices = squareVertices;
mGLTextureI = GLES20.GL_TEXTURE0;
mGLTextureII = GLES20.GL_TEXTURE1;
mGLTextureIII = GLES20.GL_TEXTURE2;
mGLIndexI = 0;
mGLIndexII = 1;
mGLTIndexIII = 2;
break;
}
}
public boolean isProgramBuilt() {
return isProgBuilt;
}
public void buildProgram() {
if (mGLProgram <= 0) {
mGLProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
}
/*
* get handle for "vPosition" and "a_texCoord"
*/
try {
mPositionHandle = GLES20.glGetAttribLocation(mGLProgram, "vPosition");
checkGlError("glGetAttribLocation vPosition");
if (mPositionHandle == -1) {
throw new RuntimeException("Could not get attribute location for vPosition");
}
mCoordHandle = GLES20.glGetAttribLocation(mGLProgram, "a_texCoord");
checkGlError("glGetAttribLocation a_texCoord");
if (mCoordHandle == -1) {
throw new RuntimeException("Could not get attribute location for a_texCoord");
}
/*
* get uniform location for y/u/v, we pass data through these uniforms
*/
mYhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_y");
checkGlError("glGetUniformLocation tex_y");
if (mYhandle == -1) {
throw new RuntimeException("Could not get uniform location for tex_y");
}
mUhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_u");
checkGlError("glGetUniformLocation tex_u");
if (mUhandle == -1) {
throw new RuntimeException("Could not get uniform location for tex_u");
}
mVhandle = GLES20.glGetUniformLocation(mGLProgram, "tex_v");
checkGlError("glGetUniformLocation tex_v");
if (mVhandle == -1) {
throw new RuntimeException("Could not get uniform location for tex_v");
}
mVPMatrixHandle = GLES20.glGetUniformLocation(mGLProgram, "uMVPMatrix");
isProgBuilt = true;
} catch (RuntimeException e) {
e.printStackTrace();
}
}
public void releaseProgram() {
GLES20.glUseProgram(0);
if (mGLProgram >= 0) {
GLES20.glDeleteProgram(mGLProgram);
}
mGLProgram = -1;
isProgBuilt = false;
}
/**
* build a set of textures, one for R, one for G, and one for B.
*/
public void buildTextures(Buffer y, Buffer u, Buffer v, int width, int height) {
boolean videoSizeChanged = (width != mVideoWidth || height != mVideoHeight);
if (videoSizeChanged) {
mVideoWidth = width;
mVideoHeight = height;
}
// building texture for Y data
if (mYtid < 0 || videoSizeChanged) {
if (mYtid >= 0) {
GLES20.glDeleteTextures(1, new int[]{mYtid}, 0);
checkGlError("glDeleteTextures");
}
// GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
checkGlError("glGenTextures");
mYtid = textures[0];
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mYtid);
checkGlError("glBindTexture");
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
mVideoWidth,
mVideoHeight,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
y);
checkGlError("glTexImage2D");
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// building texture for U data
if (mUtid < 0 || videoSizeChanged) {
if (mUtid >= 0) {
GLES20.glDeleteTextures(1, new int[]{mUtid}, 0);
checkGlError("glDeleteTextures");
}
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
checkGlError("glGenTextures");
mUtid = textures[0];
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mUtid);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
mVideoWidth / 2,
mVideoHeight / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
u);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// building texture for V data
if (mVtid < 0 || videoSizeChanged) {
if (mVtid >= 0) {
GLES20.glDeleteTextures(1, new int[]{mVtid}, 0);
checkGlError("glDeleteTextures");
}
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
checkGlError("glGenTextures");
mVtid = textures[0];
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mVtid);
GLES20.glTexImage2D(
GLES20.GL_TEXTURE_2D,
0,
GLES20.GL_LUMINANCE,
mVideoWidth / 2,
mVideoHeight / 2,
0,
GLES20.GL_LUMINANCE,
GLES20.GL_UNSIGNED_BYTE,
v);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
}
public void setDisplayOrientation(int degrees, boolean needMirror) {
if (degrees == 0) {
if (needMirror) {
mViewMatrix = s0MirrorMatrix;
} else {
mViewMatrix = s0Matrix;
}
} else if (degrees == 90) {
if (needMirror) {
mViewMatrix = s90MirrorMatrix;
} else {
mViewMatrix = s90Matrix;
}
} else if (degrees == 180) {
if (needMirror) {
mViewMatrix = s180MirrorMatrix;
} else {
mViewMatrix = s180Matrix;
}
} else if (degrees == 270) {
if (needMirror) {
mViewMatrix = s270MirrorMatrix;
} else {
mViewMatrix = s270Matrix;
}
} else {
}
}
/**
* render the frame the YUV data will be converted to RGB by shader.
*/
public void drawFrame() {
if (null == mVerticeBuffer){
return;
}
GLES20.glUseProgram(mGLProgram);
checkGlError("glUseProgram");
GLES20.glUniformMatrix4fv(mVPMatrixHandle, 1, false, mViewMatrix, 0);
GLES20.glVertexAttribPointer(mPositionHandle, 2, GLES20.GL_FLOAT, false, 8, mVerticeBuffer);
checkGlError("glVertexAttribPointer mPositionHandle");
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mCoordHandle, 2, GLES20.GL_FLOAT, false, 8, mCoordBuffer);
checkGlError("glVertexAttribPointer maTextureHandle");
GLES20.glEnableVertexAttribArray(mCoordHandle);
// bind textures
GLES20.glActiveTexture(mGLTextureI);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mYtid);
GLES20.glUniform1i(mYhandle, mGLIndexI);
GLES20.glActiveTexture(mGLTextureII);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mUtid);
GLES20.glUniform1i(mUhandle, mGLIndexII);
GLES20.glActiveTexture(mGLTextureIII);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mVtid);
GLES20.glUniform1i(mVhandle, mGLTIndexIII);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glFinish();
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mCoordHandle);
}
/**
* create program and load shaders, fragment shader is very important.
*/
public int createProgram(String vertexSource, String fragmentSource) {
// create shaders
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
// just check
int program = GLES20.glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
GLES20.glAttachShader(program, pixelShader);
checkGlError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
/**
* create shader with given source.
*/
private int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
/**
* these two buffers are used for holding vertices, screen vertices and texture vertices.
*/
void createBuffers(float[] vert) {
mVerticeBuffer = ByteBuffer.allocateDirect(vert.length * 4);
mVerticeBuffer.order(ByteOrder.nativeOrder());
mVerticeBuffer.asFloatBuffer().put(vert);
mVerticeBuffer.position(0);
if (mCoordBuffer == null) {
mCoordBuffer = ByteBuffer.allocateDirect(coordVertices.length * 4);
mCoordBuffer.order(ByteOrder.nativeOrder());
mCoordBuffer.asFloatBuffer().put(coordVertices);
mCoordBuffer.position(0);
}
}
private void checkGlError(String op) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
// throw new RuntimeException(op + ": glError " + error);
}
}
}
public static class GLFrameRenderer implements SurfaceHolder.Callback {
private static final String TAG = GLFrameRenderer.class.getSimpleName();
private static final int SFPS = 25;
private GLProgram prog = new GLProgram(0);
private int mScreenWidth;
private int mScreenHeight;
private int mVideoWidth;
private int mVideoHeight;
private ByteBuffer y;
private ByteBuffer u;
private ByteBuffer v;
private int mDisplayDegrees;
private boolean mNeedMirror = false;
private long mLastFrameTime = 0;
private long mStanderDelta;
public GLFrameRenderer() {
// mParentAct = callback;
mDisplayDegrees = 0;
mNeedMirror = false;
mStanderDelta = 1000 / SFPS;
}
public void setResolution(int nWidth, int nHeight) {
mScreenWidth = nWidth;
mScreenHeight = nHeight;
}
public void onDrawFrame() {
synchronized (this) {
if (mLastFrameTime == 0) {
mLastFrameTime = System.currentTimeMillis();
} else {
long currentTime = System.currentTimeMillis();
long delta = currentTime - mLastFrameTime;
if (delta < mStanderDelta) {
try {
sleep(mStanderDelta - delta);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mLastFrameTime = currentTime;
}
if (y != null) {
// reset position, have to be done
y.position(0);
u.position(0);
v.position(0);
prog.buildTextures(y, u, v, mVideoWidth, mVideoHeight);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
prog.drawFrame();
}
}
}
/**
* this method will be called from native code, it happens when the video is about to play or
* the video size changes.
*/
public void creatBuffer(int w, int h) {
if (mScreenWidth > 0 && mScreenHeight > 0) {
float f1 = 1f * mScreenHeight / mScreenWidth;
float f2 = 1f * h / w;
if (f1 == f2) {
prog.createBuffers(GLProgram.squareVertices);
} else if (f1 < f2) {
float widScale = f1 / f2;
prog.createBuffers(
new float[]{
-widScale, -1.0f, widScale, -1.0f, -widScale, 1.0f, widScale, 1.0f,
});
} else {
float heightScale = f2 / f1;
prog.createBuffers(
new float[]{
-1.0f, -heightScale, 1.0f, -heightScale, -1.0f, heightScale, 1.0f, heightScale,
});
}
}
if (w != mVideoWidth && h != mVideoHeight) {
this.mVideoWidth = w;
this.mVideoHeight = h;
int yarraySize = w * h;
int uvarraySize = yarraySize / 4;
synchronized (this) {
y = ByteBuffer.allocate(yarraySize);
byte[] yInit = new byte[yarraySize];
Arrays.fill(yInit, (byte) 0);
y.put(yInit);
byte[] uvInit = new byte[uvarraySize];
Arrays.fill(uvInit, (byte) 128);
u = ByteBuffer.allocate(uvarraySize);
u.put(uvInit);
v = ByteBuffer.allocate(uvarraySize);
v.put(uvInit);
}
}
}
/**
* this method will be called from native code, it's used for passing yuv data to me.
*/
public void update(byte[] ydata, byte[] udata, byte[] vdata) {
synchronized (this) {
y.clear();
u.clear();
v.clear();
y.put(ydata, 0, ydata.length);
u.put(udata, 0, udata.length);
v.put(vdata, 0, vdata.length);
}
}
public void update(byte[] yuv420p) {
synchronized (this) {
y.clear();
u.clear();
v.clear();
int size = this.mVideoWidth * this.mVideoHeight;
y.put(yuv420p, 0, size);
u.put(yuv420p, size, size / 4);
v.put(yuv420p, size * 5 / 4, size / 4);
}
}
public void setDisplayOrientation(int displayOrientation) {
mDisplayDegrees = displayOrientation;
prog.setDisplayOrientation(displayOrientation, mNeedMirror);
}
public void displayMirror(boolean mirror) {
mNeedMirror = mirror;
prog.setDisplayOrientation(mDisplayDegrees, mNeedMirror);
}
public void release() {
prog.releaseProgram();
}
public void creatProgram() {
Log.e(TAG, "GLFrameRenderer :: onSurfaceCreated");
if (!prog.isProgramBuilt()) {
prog.buildProgram();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
public static class GLES20Support {
public static boolean detectOpenGLES20(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
return (info.reqGlEsVersion >= 0x20000);
}
public static Dialog getNoSupportGLES20Dialog(final Activity activity) {
AlertDialog.Builder b = new AlertDialog.Builder(activity);
b.setCancelable(false);
b.setTitle("no opengl");
b.setMessage("not support opengl");
b.setNegativeButton(
"exit",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
activity.finish();
}
});
return b.create();
}
}
}