Mega Code Archive

 
Categories / Android / 2D Graphics
 

Check for OpenGL ES 2 0 support at runtime, and then use either OpenGL ES 1 0 or OpenGL ES 2 0, as appropriate

/*  * Copyright (C) 2009 The Android Open Source Project  *  * Licensed under the Apache License, Version 2.0 (the "License");  * you may not use this file except in compliance with the License.  * You may obtain a copy of the License at  *  *      http://www.apache.org/licenses/LICENSE-2.0  *  * Unless required by applicable law or agreed to in writing, software  * distributed under the License is distributed on an "AS IS" BASIS,  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  */ package app.test; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.GLU; import android.opengl.GLUtils; import android.opengl.Matrix; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; class GLES20TriangleRenderer implements GLSurfaceView.Renderer {   public GLES20TriangleRenderer(Context context) {     mContext = context;     mTriangleVertices = ByteBuffer         .allocateDirect(mTriangleVerticesData.length * FLOAT_SIZE_BYTES)         .order(ByteOrder.nativeOrder()).asFloatBuffer();     mTriangleVertices.put(mTriangleVerticesData).position(0);   }   public void onDrawFrame(GL10 glUnused) {     // Ignore the passed-in GL10 interface, and use the GLES20     // class's static methods instead.     GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);     GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);     GLES20.glUseProgram(mProgram);     checkGlError("glUseProgram");     GLES20.glActiveTexture(GLES20.GL_TEXTURE0);     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);     mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);     GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,         false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);     checkGlError("glVertexAttribPointer maPosition");     mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);     GLES20.glEnableVertexAttribArray(maPositionHandle);     checkGlError("glEnableVertexAttribArray maPositionHandle");     GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT,         false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);     checkGlError("glVertexAttribPointer maTextureHandle");     GLES20.glEnableVertexAttribArray(maTextureHandle);     checkGlError("glEnableVertexAttribArray maTextureHandle");     long time = SystemClock.uptimeMillis() % 4000L;     float angle = 0.090f * ((int) time);     Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);     Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);     Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);     GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);     GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);     checkGlError("glDrawArrays");   }   public void onSurfaceChanged(GL10 glUnused, int width, int height) {     // Ignore the passed-in GL10 interface, and use the GLES20     // class's static methods instead.     GLES20.glViewport(0, 0, width, height);     float ratio = (float) width / height;     Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);   }   public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {     // Ignore the passed-in GL10 interface, and use the GLES20     // class's static methods instead.     mProgram = createProgram(mVertexShader, mFragmentShader);     if (mProgram == 0) {       return;     }     maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");     checkGlError("glGetAttribLocation aPosition");     if (maPositionHandle == -1) {       throw new RuntimeException(           "Could not get attrib location for aPosition");     }     maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");     checkGlError("glGetAttribLocation aTextureCoord");     if (maTextureHandle == -1) {       throw new RuntimeException(           "Could not get attrib location for aTextureCoord");     }     muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");     checkGlError("glGetUniformLocation uMVPMatrix");     if (muMVPMatrixHandle == -1) {       throw new RuntimeException(           "Could not get attrib location for uMVPMatrix");     }     /*      * Create our texture. This has to be done each time the surface is      * created.      */     int[] textures = new int[1];     GLES20.glGenTextures(1, textures, 0);     mTextureID = textures[0];     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);     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_REPEAT);     GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,         GLES20.GL_REPEAT);     InputStream is = mContext.getResources().openRawResource(R.raw.robot);     Bitmap bitmap;     try {       bitmap = BitmapFactory.decodeStream(is);     } finally {       try {         is.close();       } catch (IOException e) {         // Ignore.       }     }     GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);     bitmap.recycle();     Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);   }   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) {         Log.e(TAG, "Could not compile shader " + shaderType + ":");         Log.e(TAG, GLES20.glGetShaderInfoLog(shader));         GLES20.glDeleteShader(shader);         shader = 0;       }     }     return shader;   }   private int createProgram(String vertexSource, String fragmentSource) {     int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);     if (vertexShader == 0) {       return 0;     }     int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);     if (pixelShader == 0) {       return 0;     }     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) {         Log.e(TAG, "Could not link program: ");         Log.e(TAG, GLES20.glGetProgramInfoLog(program));         GLES20.glDeleteProgram(program);         program = 0;       }     }     return program;   }   private void checkGlError(String op) {     int error;     while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {       Log.e(TAG, op + ": glError " + error);       throw new RuntimeException(op + ": glError " + error);     }   }   private static final int FLOAT_SIZE_BYTES = 4;   private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;   private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;   private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;   private final float[] mTriangleVerticesData = {       // X, Y, Z, U, V       -1.0f, -0.5f, 0, -0.5f, 0.0f, 1.0f, -0.5f, 0, 1.5f, -0.0f, 0.0f,       1.11803399f, 0, 0.5f, 1.61803399f };   private FloatBuffer mTriangleVertices;   private final String mVertexShader = "uniform mat4 uMVPMatrix;\n"       + "attribute vec4 aPosition;\n" + "attribute vec2 aTextureCoord;\n"       + "varying vec2 vTextureCoord;\n" + "void main() {\n"       + "  gl_Position = uMVPMatrix * aPosition;\n"       + "  vTextureCoord = aTextureCoord;\n" + "}\n";   private final String mFragmentShader = "precision mediump float;\n"       + "varying vec2 vTextureCoord;\n" + "uniform sampler2D sTexture;\n"       + "void main() {\n"       + "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + "}\n";   private float[] mMVPMatrix = new float[16];   private float[] mProjMatrix = new float[16];   private float[] mMMatrix = new float[16];   private float[] mVMatrix = new float[16];   private int mProgram;   private int mTextureID;   private int muMVPMatrixHandle;   private int maPositionHandle;   private int maTextureHandle;   private Context mContext;   private static String TAG = "GLES20TriangleRenderer"; } class TriangleRenderer implements GLSurfaceView.Renderer {   public TriangleRenderer(Context context) {     mContext = context;     mTriangle = new Triangle();   }   public void onSurfaceCreated(GL10 gl, EGLConfig config) {     /*      * By default, OpenGL enables features that improve quality but reduce      * performance. One might want to tweak that especially on software      * renderer.      */     gl.glDisable(GL10.GL_DITHER);     /*      * Some one-time OpenGL initialization can be made here probably based      * on features of this particular context      */     gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);     gl.glClearColor(.5f, .5f, .5f, 1);     gl.glShadeModel(GL10.GL_SMOOTH);     gl.glEnable(GL10.GL_DEPTH_TEST);     gl.glEnable(GL10.GL_TEXTURE_2D);     /*      * Create our texture. This has to be done each time the surface is      * created.      */     int[] textures = new int[1];     gl.glGenTextures(1, textures, 0);     mTextureID = textures[0];     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,         GL10.GL_NEAREST);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,         GL10.GL_LINEAR);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,         GL10.GL_CLAMP_TO_EDGE);     gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,         GL10.GL_REPLACE);     InputStream is = mContext.getResources().openRawResource(R.raw.robot);     Bitmap bitmap;     try {       bitmap = BitmapFactory.decodeStream(is);     } finally {       try {         is.close();       } catch (IOException e) {         // Ignore.       }     }     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);     bitmap.recycle();   }   public void onDrawFrame(GL10 gl) {     /*      * By default, OpenGL enables features that improve quality but reduce      * performance. One might want to tweak that especially on software      * renderer.      */     gl.glDisable(GL10.GL_DITHER);     gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,         GL10.GL_MODULATE);     /*      * Usually, the first thing one might want to do is to clear the screen.      * The most efficient way of doing this is to use glClear().      */     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);     /*      * Now we're ready to draw some 3D objects      */     gl.glMatrixMode(GL10.GL_MODELVIEW);     gl.glLoadIdentity();     GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);     gl.glActiveTexture(GL10.GL_TEXTURE0);     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);     gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,         GL10.GL_REPEAT);     gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,         GL10.GL_REPEAT);     long time = SystemClock.uptimeMillis() % 4000L;     float angle = 0.090f * ((int) time);     gl.glRotatef(angle, 0, 0, 1.0f);     mTriangle.draw(gl);   }   public void onSurfaceChanged(GL10 gl, int w, int h) {     gl.glViewport(0, 0, w, h);     /*      * Set our projection matrix. This doesn't have to be done each time we      * draw, but usually a new projection needs to be set when the viewport      * is resized.      */     float ratio = (float) w / h;     gl.glMatrixMode(GL10.GL_PROJECTION);     gl.glLoadIdentity();     gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);   }   private Context mContext;   private Triangle mTriangle;   private int mTextureID; } class Triangle {   public Triangle() {     // Buffers to be passed to gl*Pointer() functions     // must be direct, i.e., they must be placed on the     // native heap where the garbage collector cannot     // move them.     //     // Buffers with multi-byte datatypes (e.g., short, int, float)     // must have their byte order set to native order     ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);     vbb.order(ByteOrder.nativeOrder());     mFVertexBuffer = vbb.asFloatBuffer();     ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);     tbb.order(ByteOrder.nativeOrder());     mTexBuffer = tbb.asFloatBuffer();     ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);     ibb.order(ByteOrder.nativeOrder());     mIndexBuffer = ibb.asShortBuffer();     // A unit-sided equalateral triangle centered on the origin.     float[] coords = {         // X, Y, Z         -0.5f, -0.25f, 0, 0.5f, -0.25f, 0, 0.0f, 0.559016994f, 0 };     for (int i = 0; i < VERTS; i++) {       for (int j = 0; j < 3; j++) {         mFVertexBuffer.put(coords[i * 3 + j] * 2.0f);       }     }     for (int i = 0; i < VERTS; i++) {       for (int j = 0; j < 2; j++) {         mTexBuffer.put(coords[i * 3 + j] * 2.0f + 0.5f);       }     }     for (int i = 0; i < VERTS; i++) {       mIndexBuffer.put((short) i);     }     mFVertexBuffer.position(0);     mTexBuffer.position(0);     mIndexBuffer.position(0);   }   public void draw(GL10 gl) {     gl.glFrontFace(GL10.GL_CCW);     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);     gl.glEnable(GL10.GL_TEXTURE_2D);     gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);     gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS,         GL10.GL_UNSIGNED_SHORT, mIndexBuffer);   }   private final static int VERTS = 3;   private FloatBuffer mFVertexBuffer;   private FloatBuffer mTexBuffer;   private ShortBuffer mIndexBuffer; } /**  * This sample shows how to check for OpenGL ES 2.0 support at runtime, and then  * use either OpenGL ES 1.0 or OpenGL ES 2.0, as appropriate.  */ public class Test extends Activity {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     mGLSurfaceView = new GLSurfaceView(this);     if (detectOpenGLES20()) {       // Tell the surface view we want to create an OpenGL ES       // 2.0-compatible       // context, and set an OpenGL ES 2.0-compatible renderer.       mGLSurfaceView.setEGLContextClientVersion(2);       mGLSurfaceView.setRenderer(new GLES20TriangleRenderer(this));     } else {       // Set an OpenGL ES 1.x-compatible renderer. In a real application       // this renderer might approximate the same output as the 2.0       // renderer.       mGLSurfaceView.setRenderer(new TriangleRenderer(this));     }     setContentView(mGLSurfaceView);   }   private boolean detectOpenGLES20() {     ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);     ConfigurationInfo info = am.getDeviceConfigurationInfo();     return (info.reqGlEsVersion >= 0x20000);   }   @Override   protected void onResume() {     // Ideally a game should implement onResume() and onPause()     // to take appropriate action when the activity looses focus     super.onResume();     mGLSurfaceView.onResume();   }   @Override   protected void onPause() {     // Ideally a game should implement onResume() and onPause()     // to take appropriate action when the activity looses focus     super.onPause();     mGLSurfaceView.onPause();   }   private GLSurfaceView mGLSurfaceView; }