Home | History | Annotate | Download | only in basicglsurfaceview
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.basicglsurfaceview;
     18 
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.nio.ByteBuffer;
     22 import java.nio.ByteOrder;
     23 import java.nio.FloatBuffer;
     24 
     25 import javax.microedition.khronos.egl.EGLConfig;
     26 import javax.microedition.khronos.opengles.GL10;
     27 
     28 import android.content.Context;
     29 import android.graphics.Bitmap;
     30 import android.graphics.BitmapFactory;
     31 import android.opengl.GLES20;
     32 import android.opengl.GLSurfaceView;
     33 import android.opengl.GLUtils;
     34 import android.opengl.Matrix;
     35 import android.os.SystemClock;
     36 import android.util.Log;
     37 
     38 class GLES20TriangleRenderer implements GLSurfaceView.Renderer {
     39 
     40     public GLES20TriangleRenderer(Context context) {
     41         mContext = context;
     42         mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
     43                 * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
     44         mTriangleVertices.put(mTriangleVerticesData).position(0);
     45     }
     46 
     47     public void onDrawFrame(GL10 glUnused) {
     48         // Ignore the passed-in GL10 interface, and use the GLES20
     49         // class's static methods instead.
     50         GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
     51         GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
     52         GLES20.glUseProgram(mProgram);
     53         checkGlError("glUseProgram");
     54 
     55         GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
     56         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
     57 
     58         mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
     59         GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
     60                 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
     61         checkGlError("glVertexAttribPointer maPosition");
     62         mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
     63         GLES20.glEnableVertexAttribArray(maPositionHandle);
     64         checkGlError("glEnableVertexAttribArray maPositionHandle");
     65         GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
     66                 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
     67         checkGlError("glVertexAttribPointer maTextureHandle");
     68         GLES20.glEnableVertexAttribArray(maTextureHandle);
     69         checkGlError("glEnableVertexAttribArray maTextureHandle");
     70 
     71         long time = SystemClock.uptimeMillis() % 4000L;
     72         float angle = 0.090f * ((int) time);
     73         Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
     74         Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
     75         Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
     76 
     77         GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
     78         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
     79         checkGlError("glDrawArrays");
     80     }
     81 
     82     public void onSurfaceChanged(GL10 glUnused, int width, int height) {
     83         // Ignore the passed-in GL10 interface, and use the GLES20
     84         // class's static methods instead.
     85         GLES20.glViewport(0, 0, width, height);
     86         float ratio = (float) width / height;
     87         Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
     88     }
     89 
     90     public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
     91         // Ignore the passed-in GL10 interface, and use the GLES20
     92         // class's static methods instead.
     93         mProgram = createProgram(mVertexShader, mFragmentShader);
     94         if (mProgram == 0) {
     95             return;
     96         }
     97         maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
     98         checkGlError("glGetAttribLocation aPosition");
     99         if (maPositionHandle == -1) {
    100             throw new RuntimeException("Could not get attrib location for aPosition");
    101         }
    102         maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
    103         checkGlError("glGetAttribLocation aTextureCoord");
    104         if (maTextureHandle == -1) {
    105             throw new RuntimeException("Could not get attrib location for aTextureCoord");
    106         }
    107 
    108         muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    109         checkGlError("glGetUniformLocation uMVPMatrix");
    110         if (muMVPMatrixHandle == -1) {
    111             throw new RuntimeException("Could not get attrib location for uMVPMatrix");
    112         }
    113 
    114         /*
    115          * Create our texture. This has to be done each time the
    116          * surface is created.
    117          */
    118 
    119         int[] textures = new int[1];
    120         GLES20.glGenTextures(1, textures, 0);
    121 
    122         mTextureID = textures[0];
    123         GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
    124 
    125         GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
    126                 GLES20.GL_NEAREST);
    127         GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
    128                 GLES20.GL_TEXTURE_MAG_FILTER,
    129                 GLES20.GL_LINEAR);
    130 
    131         GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
    132                 GLES20.GL_REPEAT);
    133         GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
    134                 GLES20.GL_REPEAT);
    135 
    136         InputStream is = mContext.getResources()
    137             .openRawResource(R.raw.robot);
    138         Bitmap bitmap;
    139         try {
    140             bitmap = BitmapFactory.decodeStream(is);
    141         } finally {
    142             try {
    143                 is.close();
    144             } catch(IOException e) {
    145                 // Ignore.
    146             }
    147         }
    148 
    149         GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    150         bitmap.recycle();
    151 
    152         Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    153     }
    154 
    155     private int loadShader(int shaderType, String source) {
    156         int shader = GLES20.glCreateShader(shaderType);
    157         if (shader != 0) {
    158             GLES20.glShaderSource(shader, source);
    159             GLES20.glCompileShader(shader);
    160             int[] compiled = new int[1];
    161             GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
    162             if (compiled[0] == 0) {
    163                 Log.e(TAG, "Could not compile shader " + shaderType + ":");
    164                 Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
    165                 GLES20.glDeleteShader(shader);
    166                 shader = 0;
    167             }
    168         }
    169         return shader;
    170     }
    171 
    172     private int createProgram(String vertexSource, String fragmentSource) {
    173         int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
    174         if (vertexShader == 0) {
    175             return 0;
    176         }
    177 
    178         int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
    179         if (pixelShader == 0) {
    180             return 0;
    181         }
    182 
    183         int program = GLES20.glCreateProgram();
    184         if (program != 0) {
    185             GLES20.glAttachShader(program, vertexShader);
    186             checkGlError("glAttachShader");
    187             GLES20.glAttachShader(program, pixelShader);
    188             checkGlError("glAttachShader");
    189             GLES20.glLinkProgram(program);
    190             int[] linkStatus = new int[1];
    191             GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
    192             if (linkStatus[0] != GLES20.GL_TRUE) {
    193                 Log.e(TAG, "Could not link program: ");
    194                 Log.e(TAG, GLES20.glGetProgramInfoLog(program));
    195                 GLES20.glDeleteProgram(program);
    196                 program = 0;
    197             }
    198         }
    199         return program;
    200     }
    201 
    202     private void checkGlError(String op) {
    203         int error;
    204         while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
    205             Log.e(TAG, op + ": glError " + error);
    206             throw new RuntimeException(op + ": glError " + error);
    207         }
    208     }
    209 
    210     private static final int FLOAT_SIZE_BYTES = 4;
    211     private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
    212     private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
    213     private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
    214     private final float[] mTriangleVerticesData = {
    215             // X, Y, Z, U, V
    216             -1.0f, -0.5f, 0, -0.5f, 0.0f,
    217             1.0f, -0.5f, 0, 1.5f, -0.0f,
    218             0.0f,  1.11803399f, 0, 0.5f,  1.61803399f };
    219 
    220     private FloatBuffer mTriangleVertices;
    221 
    222     private final String mVertexShader =
    223         "uniform mat4 uMVPMatrix;\n" +
    224         "attribute vec4 aPosition;\n" +
    225         "attribute vec2 aTextureCoord;\n" +
    226         "varying vec2 vTextureCoord;\n" +
    227         "void main() {\n" +
    228         "  gl_Position = uMVPMatrix * aPosition;\n" +
    229         "  vTextureCoord = aTextureCoord;\n" +
    230         "}\n";
    231 
    232     private final String mFragmentShader =
    233         "precision mediump float;\n" +
    234         "varying vec2 vTextureCoord;\n" +
    235         "uniform sampler2D sTexture;\n" +
    236         "void main() {\n" +
    237         "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
    238         "}\n";
    239 
    240     private float[] mMVPMatrix = new float[16];
    241     private float[] mProjMatrix = new float[16];
    242     private float[] mMMatrix = new float[16];
    243     private float[] mVMatrix = new float[16];
    244 
    245     private int mProgram;
    246     private int mTextureID;
    247     private int muMVPMatrixHandle;
    248     private int maPositionHandle;
    249     private int maTextureHandle;
    250 
    251     private Context mContext;
    252     private static String TAG = "GLES20TriangleRenderer";
    253 }
    254