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