111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown/*
211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * Copyright (C) 2012 The Android Open Source Project
311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown *
411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * you may not use this file except in compliance with the License.
611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * You may obtain a copy of the License at
711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown *
811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown *
1011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * Unless required by applicable law or agreed to in writing, software
1111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * See the License for the specific language governing permissions and
1411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * limitations under the License.
1511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown */
1611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
1711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownpackage com.android.dreams.basic;
1811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
1911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.graphics.Color;
2011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.graphics.SurfaceTexture;
2111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.util.Log;
2211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.view.Choreographer;
23c3441bcb11dc414911dd5681fd01ca1d2dde74d2Leif Hendrik Wildenimport android.view.Surface;
2411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.os.SystemClock;
2511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
2611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport javax.microedition.khronos.egl.EGL10;
2711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport javax.microedition.khronos.egl.EGLConfig;
2811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport javax.microedition.khronos.egl.EGLContext;
2911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport javax.microedition.khronos.egl.EGLDisplay;
3011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport javax.microedition.khronos.egl.EGLSurface;
3111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
3211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.opengl.EGL14;
3311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport android.opengl.GLUtils;
3411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
3511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport java.nio.ByteBuffer;
3611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport java.nio.ByteOrder;
3711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport java.nio.FloatBuffer;
3811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport java.nio.ShortBuffer;
3911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
4011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownimport static android.opengl.GLES20.*;
4111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
4211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown/**
4311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * The OpenGL renderer for the {@link Colors} dream.
4411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * <p>
4511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * This class is single-threaded.  Its methods must only be called on the
4611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * rendering thread.
4711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown * </p>
4811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown */
4911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brownfinal class ColorsGLRenderer implements Choreographer.FrameCallback {
5011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    static final String TAG = ColorsGLRenderer.class.getSimpleName();
5111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    static final boolean DEBUG = false;
5211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
53a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy    private static void LOG(String fmt, Object... args) {
5411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!DEBUG) return;
5511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        Log.v(TAG, String.format(fmt, args));
5611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
5711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
58c3441bcb11dc414911dd5681fd01ca1d2dde74d2Leif Hendrik Wilden    private final Surface mSurface;
5911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private int mWidth;
6011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private int mHeight;
6111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
6211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private final Choreographer mChoreographer;
6311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
6411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private Square mSquare;
6511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private long mLastFrameTime;
6611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private int mFrameNum = 0;
6711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
6811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    // It's so easy to use OpenGLES 2.0!
6911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private EGL10 mEgl;
7011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private EGLDisplay mEglDisplay;
7111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private EGLContext mEglContext;
7211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private EGLSurface mEglSurface;
7311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
74c3441bcb11dc414911dd5681fd01ca1d2dde74d2Leif Hendrik Wilden    public ColorsGLRenderer(Surface surface, int width, int height) {
7511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mSurface = surface;
7611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mWidth = width;
7711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mHeight = height;
7811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
7911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mChoreographer = Choreographer.getInstance();
8011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
8111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
8211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    public void start() {
8311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        initGL();
8411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mSquare = new Square();
8511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
8611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mFrameNum = 0;
8711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mChoreographer.postFrameCallback(this);
8811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
8911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
9011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    public void stop() {
9111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mChoreographer.removeFrameCallback(this);
9211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
9311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mSquare = null;
9411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        finishGL();
9511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
9611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
9711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    public void setSize(int width, int height) {
9811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mWidth = width;
9911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mHeight = height;
10011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
10111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
10211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    @Override
10311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    public void doFrame(long frameTimeNanos) {
10411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mFrameNum += 1;
10511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
10611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // Clear on first frame.
10711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (mFrameNum == 1) {
10811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glClearColor(1f, 0f, 0f, 1.0f);
10911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            if (DEBUG) {
11011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                mLastFrameTime = frameTimeNanos;
11111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
11211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
11311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
11411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // Draw new frame.
11511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkCurrent();
11611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
11711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glViewport(0, 0, mWidth, mHeight);
11811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
11911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (DEBUG) {
120a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy            final long dt = frameTimeNanos - mLastFrameTime;
12111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            final int fps = (int) (1e9f / dt);
12211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            if (0 == (mFrameNum % 10)) {
12311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                LOG("frame %d fps=%d", mFrameNum, fps);
12411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
12511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            if (fps < 40) {
12611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                LOG("JANK! (%d ms)", dt);
12711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
128a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy            mLastFrameTime = frameTimeNanos;
12911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
13011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
13111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glClear(GL_COLOR_BUFFER_BIT);
13211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
13311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
13411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mSquare.draw();
13511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
13611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
13711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("Cannot swap buffers");
13811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
13911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkEglError();
14011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
14111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // Animate.  Post callback to run on next vsync.
14211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mChoreographer.postFrameCallback(this);
14311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
14411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
14511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private void checkCurrent() {
14611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
14711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
14811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
14911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                throw new RuntimeException("eglMakeCurrent failed "
15011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
15111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
15211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
15311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
15411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
15511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private void initGL() {
15611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mEgl = (EGL10) EGLContext.getEGL();
15711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
15811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
15911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
16011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("eglGetDisplay failed "
16111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
16211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
16311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
16411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] version = new int[2];
16511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!mEgl.eglInitialize(mEglDisplay, version)) {
16611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("eglInitialize failed " +
16711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
16811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
16911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
170a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy        EGLConfig eglConfig = chooseEglConfig();
171a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy        if (eglConfig == null) {
17211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("eglConfig not initialized");
17311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
17411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
175a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy        mEglContext = createContext(mEgl, mEglDisplay, eglConfig);
17611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
177a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, eglConfig, mSurface, null);
17811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
17911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
18011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            int error = mEgl.eglGetError();
18111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
18211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
18311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                return;
18411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
18511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("createWindowSurface failed "
18611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    + GLUtils.getEGLErrorString(error));
18711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
18811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
18911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
19011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new RuntimeException("eglMakeCurrent failed "
19111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
19211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
19311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
19411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
19511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private void finishGL() {
19611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
19711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
19811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
19911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
200a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy    private static EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
20111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] attrib_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
20211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
20311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
20411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
20511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private EGLConfig chooseEglConfig() {
20611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] configsCount = new int[1];
20711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        EGLConfig[] configs = new EGLConfig[1];
20811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] configSpec = getConfig();
20911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
21011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            throw new IllegalArgumentException("eglChooseConfig failed " +
21111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
21211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        } else if (configsCount[0] > 0) {
21311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            return configs[0];
21411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
21511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        return null;
21611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
21711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
21811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private static int[] getConfig() {
21911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        return new int[] {
22011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
22111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_RED_SIZE, 8,
22211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_GREEN_SIZE, 8,
22311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_BLUE_SIZE, 8,
224a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy                EGL10.EGL_ALPHA_SIZE, 0,
22511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_DEPTH_SIZE, 0,
22611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_STENCIL_SIZE, 0,
22711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                EGL10.EGL_NONE
22811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        };
22911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
23011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
23111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private static int buildProgram(String vertex, String fragment) {
23211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
23311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (vertexShader == 0) return 0;
23411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
23511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
23611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (fragmentShader == 0) return 0;
23711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
23811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int program = glCreateProgram();
23911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glAttachShader(program, vertexShader);
24011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
24111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
24211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glAttachShader(program, fragmentShader);
24311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
24411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
24511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glLinkProgram(program);
24611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
24711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
24811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] status = new int[1];
24911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glGetProgramiv(program, GL_LINK_STATUS, status, 0);
25011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (status[0] != GL_TRUE) {
25111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            String error = glGetProgramInfoLog(program);
25211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            Log.d(TAG, "Error while linking program:\n" + error);
25311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glDeleteShader(vertexShader);
25411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glDeleteShader(fragmentShader);
25511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glDeleteProgram(program);
25611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            return 0;
25711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
25811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
25911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        return program;
26011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
26111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
26211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private static int buildShader(String source, int type) {
26311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int shader = glCreateShader(type);
26411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
26511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glShaderSource(shader, source);
26611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
26711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
26811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glCompileShader(shader);
26911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError();
27011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
27111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int[] status = new int[1];
27211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
27311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (status[0] != GL_TRUE) {
27411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            String error = glGetShaderInfoLog(shader);
27511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            Log.d(TAG, "Error while compiling shader:\n" + error);
27611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glDeleteShader(shader);
27711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            return 0;
27811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
27911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
28011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        return shader;
28111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
28211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
28311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private void checkEglError() {
28411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int error = mEgl.eglGetError();
28511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (error != EGL10.EGL_SUCCESS) {
28611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            Log.w(TAG, "EGL error = 0x" + Integer.toHexString(error));
28711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
28811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
28911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
29011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private static void checkGlError() {
29111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        checkGlError("");
29211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
29311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
29411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private static void checkGlError(String what) {
29511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        int error = glGetError();
29611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        if (error != GL_NO_ERROR) {
29711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            Log.w(TAG, "GL error: (" + what + ") = 0x" + Integer.toHexString(error));
29811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
29911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
30011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
30111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    private final static class Square {
30211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // Straight from the API guide
30311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final String vertexShaderCode =
30411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "attribute vec4 a_position;" +
30511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "attribute vec4 a_color;" +
30611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "varying vec4 v_color;" +
30711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "void main() {" +
30811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "  gl_Position = a_position;" +
30911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "  v_color = a_color;" +
31011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "}";
31111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
31211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final String fragmentShaderCode =
31311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "precision mediump float;" +
31411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "varying vec4 v_color;" +
31511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "void main() {" +
31611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "  gl_FragColor = v_color;" +
31711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            "}";
31811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
31911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final FloatBuffer vertexBuffer;
32011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final FloatBuffer colorBuffer;
32111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final int mProgram;
32211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private int mPositionHandle;
32311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private int mColorHandle;
32411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
32511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private ShortBuffer drawListBuffer;
32611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
32711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
32811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // number of coordinates per vertex in this array
32911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        final int COORDS_PER_VERTEX = 3;
33011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        float squareCoords[] = { -1f,  1f, 0f,   // top left
33111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                                 -1f, -1f, 0f,   // bottom left
33211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                                  1f, -1f, 0f,   // bottom right
33311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                                  1f,  1f, 0f }; // top right
33411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
33511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices (CCW)
33611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
33711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final float HUES[] = { // reverse order due to CCW winding
33811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                60,  // yellow
33911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                120, // green
34011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                343, // red
34111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                200, // blue
34211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        };
34311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
34411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final int vertexCount = squareCoords.length / COORDS_PER_VERTEX;
34511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex
34611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
34711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private float cornerFrequencies[] = new float[vertexCount];
34811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private int cornerRotation;
34911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
35011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        final int COLOR_PLANES_PER_VERTEX = 4;
35111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        private final int colorStride = COLOR_PLANES_PER_VERTEX * 4; // bytes per vertex
35211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
35311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        // Set color with red, green, blue and alpha (opacity) values
354a042f4a114a5fd728fa3aa8539e377727860f1d9Romain Guy        // float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
35511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
35611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        public Square() {
35711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            for (int i=0; i<vertexCount; i++) {
35811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                cornerFrequencies[i] = 1f + (float)(Math.random() * 5);
35911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
36011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            cornerRotation = (int)(Math.random() * vertexCount);
36111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // initialize vertex byte buffer for shape coordinates
36211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            ByteBuffer bb = ByteBuffer.allocateDirect(
36311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // (# of coordinate values * 4 bytes per float)
36411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    squareCoords.length * 4);
36511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            bb.order(ByteOrder.nativeOrder());
36611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            vertexBuffer = bb.asFloatBuffer();
36711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            vertexBuffer.put(squareCoords);
36811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            vertexBuffer.position(0);
36911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
37011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            bb = ByteBuffer.allocateDirect(vertexCount * colorStride);
37111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            bb.order(ByteOrder.nativeOrder());
37211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            colorBuffer = bb.asFloatBuffer();
37311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
37411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // initialize byte buffer for the draw list
37511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            ByteBuffer dlb = ByteBuffer.allocateDirect(
37611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // (# of coordinate values * 2 bytes per short)
37711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    drawOrder.length * 2);
37811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            dlb.order(ByteOrder.nativeOrder());
37911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            drawListBuffer = dlb.asShortBuffer();
38011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            drawListBuffer.put(drawOrder);
38111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            drawListBuffer.position(0);
38211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
38311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            mProgram = buildProgram(vertexShaderCode, fragmentShaderCode);
38411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
38511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // Add program to OpenGL environment
38611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glUseProgram(mProgram);
38711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            checkGlError("glUseProgram(" + mProgram + ")");
38811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
38911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // get handle to vertex shader's a_position member
39011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            mPositionHandle = glGetAttribLocation(mProgram, "a_position");
39111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            checkGlError("glGetAttribLocation(a_position)");
39211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
39311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // Enable a handle to the triangle vertices
39411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glEnableVertexAttribArray(mPositionHandle);
39511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
39611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // Prepare the triangle coordinate data
39711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
39811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    GL_FLOAT, false,
39911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    vertexStride, vertexBuffer);
40011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
40111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            mColorHandle = glGetAttribLocation(mProgram, "a_color");
40211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            checkGlError("glGetAttribLocation(a_color)");
40311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glEnableVertexAttribArray(mColorHandle);
40411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            checkGlError("glEnableVertexAttribArray");
40511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
40611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
40711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        final float[] _tmphsv = new float[3];
40811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        public void draw() {
40911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // same thing for colors
41011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            long now = SystemClock.uptimeMillis();
41111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            colorBuffer.clear();
41211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            final float t = now / 4000f; // set the base period to 4sec
41311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            for(int i=0; i<vertexCount; i++) {
41411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                final float freq = (float) Math.sin(2 * Math.PI * t / cornerFrequencies[i]);
41511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                _tmphsv[0] = HUES[(i + cornerRotation) % vertexCount];
41611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                _tmphsv[1] = 1f;
41711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                _tmphsv[2] = freq * 0.25f + 0.75f;
41811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                final int c = Color.HSVToColor(_tmphsv);
41911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                colorBuffer.put((float)((c & 0xFF0000) >> 16) / 0xFF);
42011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                colorBuffer.put((float)((c & 0x00FF00) >> 8) / 0xFF);
42111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                colorBuffer.put((float)(c & 0x0000FF) / 0xFF);
42211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                colorBuffer.put(/*a*/ 1f);
42311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            }
42411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            colorBuffer.position(0);
42511348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glVertexAttribPointer(mColorHandle, COLOR_PLANES_PER_VERTEX,
42611348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    GL_FLOAT, false,
42711348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown                    colorStride, colorBuffer);
42811348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            checkGlError("glVertexAttribPointer");
42911348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown
43011348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            // Draw the triangle
43111348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown            glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
43211348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown        }
43311348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown    }
43411348f99ee2ffaeb3f705b669ae886beda97656fJeff Brown}
435