150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich/*
250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * Copyright (C) 2009 The Android Open Source Project
350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * Licensed under the Apache License, Version 2.0 (the "License");
550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * you may not use this file except in compliance with the License.
650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * You may obtain a copy of the License at
750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *      http://www.apache.org/licenses/LICENSE-2.0
950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
1050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * Unless required by applicable law or agreed to in writing, software
1150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * distributed under the License is distributed on an "AS IS" BASIS,
1250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * See the License for the specific language governing permissions and
1450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * limitations under the License.
1550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich */
1650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
1750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichpackage com.android.gl2java;
1850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
1950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.content.Context;
2050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.opengl.GLSurfaceView;
2150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.util.AttributeSet;
2250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.util.Log;
2350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.view.KeyEvent;
2450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.view.MotionEvent;
2550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
2650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport java.nio.ByteBuffer;
2750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport java.nio.ByteOrder;
2850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport java.nio.FloatBuffer;
2950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
3050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport javax.microedition.khronos.egl.EGL10;
3150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport javax.microedition.khronos.egl.EGLConfig;
3250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport javax.microedition.khronos.egl.EGLContext;
3350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport javax.microedition.khronos.egl.EGLDisplay;
3450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport javax.microedition.khronos.opengles.GL10;
3550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
3650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichimport android.opengl.GLES20;
3750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
3850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich/**
3950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * An implementation of SurfaceView that uses the dedicated surface for
4050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * displaying an OpenGL animation.  This allows the animation to run in a
4150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * separate thread, without requiring that it be driven by the update mechanism
4250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * of the view hierarchy.
4350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
4450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * The application-specific rendering code is delegated to a GLView.Renderer
4550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * instance.
4650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich */
4750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichclass GL2JavaView extends GLSurfaceView {
4850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    private static String TAG = "GL2JavaView";
4950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
5050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public GL2JavaView(Context context) {
5150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        super(context);
52378112ebed362a85471bd2acb307aa0ddb539d17Jack Palevich        setEGLContextClientVersion(2);
5350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        setRenderer(new Renderer());
5450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
5550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
5650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    private static class Renderer implements GLSurfaceView.Renderer {
5750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
5850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        public Renderer() {
5950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4)
6050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                .order(ByteOrder.nativeOrder()).asFloatBuffer();
6150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            mTriangleVertices.put(mTriangleVerticesData).position(0);
6250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
6350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
6450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        public void onDrawFrame(GL10 gl) {
6550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
6650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
6750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glUseProgram(mProgram);
6850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            checkGlError("glUseProgram");
6950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
7050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTriangleVertices);
7150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            checkGlError("glVertexAttribPointer");
7250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glEnableVertexAttribArray(mvPositionHandle);
7350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            checkGlError("glEnableVertexAttribArray");
7450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
7550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            checkGlError("glDrawArrays");
7650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
7750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
7850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
7950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        public void onSurfaceChanged(GL10 gl, int width, int height) {
8050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            GLES20.glViewport(0, 0, width, height);
8150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
8250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
8350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
8450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            mProgram = createProgram(mVertexShader, mFragmentShader);
8550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (mProgram == 0) {
8650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                return;
8750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
8850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
8950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            checkGlError("glGetAttribLocation");
9050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (mvPositionHandle == -1) {
9150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                throw new RuntimeException("Could not get attrib location for vPosition");
9250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
9350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
9450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
9550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private int loadShader(int shaderType, String source) {
9650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            int shader = GLES20.glCreateShader(shaderType);
9750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (shader != 0) {
9850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glShaderSource(shader, source);
9950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glCompileShader(shader);
10050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                int[] compiled = new int[1];
10150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
10250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                if (compiled[0] == 0) {
10350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    Log.e(TAG, "Could not compile shader " + shaderType + ":");
10450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
10550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    GLES20.glDeleteShader(shader);
10650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    shader = 0;
10750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                }
10850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
10950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            return shader;
11050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
11150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
11250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private int createProgram(String vertexSource, String fragmentSource) {
11350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
11450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (vertexShader == 0) {
11550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                return 0;
11650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
11750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
11850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
11950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (pixelShader == 0) {
12050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                return 0;
12150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
12250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
12350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            int program = GLES20.glCreateProgram();
12450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            if (program != 0) {
12550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glAttachShader(program, vertexShader);
12650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                checkGlError("glAttachShader");
12750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glAttachShader(program, pixelShader);
12850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                checkGlError("glAttachShader");
12950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glLinkProgram(program);
13050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                int[] linkStatus = new int[1];
13150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
13250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                if (linkStatus[0] != GLES20.GL_TRUE) {
13350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    Log.e(TAG, "Could not link program: ");
13450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    Log.e(TAG, GLES20.glGetProgramInfoLog(program));
13550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    GLES20.glDeleteProgram(program);
13650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                    program = 0;
13750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                }
13850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
13950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            return program;
14050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
14150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
14250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private void checkGlError(String op) {
14350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            int error;
14450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
14550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                Log.e(TAG, op + ": glError " + error);
14650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                throw new RuntimeException(op + ": glError " + error);
14750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            }
14850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
14950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
15050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private final float[] mTriangleVerticesData = { 0.0f, 0.5f, -0.5f, -0.5f,
15150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich                0.5f, -0.5f };
15250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
15350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private FloatBuffer mTriangleVertices;
15450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
15550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private final String mVertexShader = "attribute vec4 vPosition;\n"
15650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "void main() {\n"
15750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "  gl_Position = vPosition;\n"
15850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "}\n";
15950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
16050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private final String mFragmentShader = "precision mediump float;\n"
16150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "void main() {\n"
16250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
16350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            + "}\n";
16450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
16550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private int mProgram;
16650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        private int mvPositionHandle;
16750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
16850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
16950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich}
17050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
171