Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7afae5c authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

Merge "Update GLTextureView sample to do something real."

parents f782ded9 d0d07059
Loading
Loading
Loading
Loading
+172 −13
Original line number Diff line number Diff line
@@ -19,13 +19,17 @@ package com.android.test.hwui;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import javax.microedition.khronos.egl.EGL10;
@@ -36,6 +40,12 @@ import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.*;

@SuppressWarnings({"UnusedDeclaration"})
public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
    private RenderThread mRenderThread;
@@ -48,12 +58,14 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa
        mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);

        setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
        setContentView(mTextureView, new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
                Gravity.CENTER));
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        mRenderThread = new RenderThread(surface);
        mRenderThread = new RenderThread(getResources(), surface);
        mRenderThread.start();

        mTextureView.setCameraDistance(5000);
@@ -97,7 +109,8 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa

        private volatile boolean mFinished;

        private SurfaceTexture mSurface;
        private final Resources mResources;
        private final SurfaceTexture mSurface;
        
        private EGL10 mEgl;
        private EGLDisplay mEglDisplay;
@@ -106,26 +119,96 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa
        private EGLSurface mEglSurface;
        private GL mGL;

        RenderThread(SurfaceTexture surface) {
        RenderThread(Resources resources, SurfaceTexture surface) {
            mResources = resources;
            mSurface = surface;
        }

        private static final String sSimpleVS =
                "attribute vec4 position;\n" +
                "attribute vec2 texCoords;\n" +
                "varying vec2 outTexCoords;\n" +
                "\nvoid main(void) {\n" +
                "    outTexCoords = texCoords;\n" +
                "    gl_Position = position;\n" +
                "}\n\n";
        private static final String sSimpleFS =
                "precision mediump float;\n\n" +
                "varying vec2 outTexCoords;\n" +
                "uniform sampler2D texture;\n" +
                "\nvoid main(void) {\n" +
                "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
                "}\n\n";

        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, -1.0f, 0, 0.f, 0.f,
                1.0f, -1.0f, 0, 1.f, 0.f,
                -1.0f,  1.0f, 0, 0.f, 1.f,
                1.0f,   1.0f, 0, 1.f, 1.f,
        };

        @Override
        public void run() {
            initGL();
            
            float red = 1.0f;
            FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
                    * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
            triangleVertices.put(mTriangleVerticesData).position(0);

            int texture = loadTexture(R.drawable.large_photo);
            int program = buildProgram(sSimpleVS, sSimpleFS);

            int attribPosition = glGetAttribLocation(program, "position");
            checkGlError();

            int attribTexCoords = glGetAttribLocation(program, "texCoords");
            checkGlError();

            int uniformTexture = glGetUniformLocation(program, "texture");
            checkGlError();

            glBindTexture(GL_TEXTURE_2D, texture);
            checkGlError();

            glUseProgram(program);
            checkGlError();

            glEnableVertexAttribArray(attribPosition);
            checkGlError();

            glEnableVertexAttribArray(attribTexCoords);
            checkGlError();

            glUniform1i(texture, 0);
            checkGlError();
            
            while (!mFinished) {
                checkCurrent();

                Log.d(LOG_TAG, "Rendering frame");

                GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f);
                glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                checkGlError();

                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
                glClear(GL_COLOR_BUFFER_BIT);
                checkGlError();

                // drawQuad
                triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
                glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);

                triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
                glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
                        TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);

                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

                if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
                    throw new RuntimeException("Cannot swap buffers");
                }
@@ -136,14 +219,90 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa
                } catch (InterruptedException e) {
                    // Ignore
                }

                red += 0.021f;
                if (red > 1.0f) red = 0.0f;
            }

            finishGL();
        }

        private int loadTexture(int resource) {
            int[] textures = new int[1];

            glActiveTexture(GL_TEXTURE0);
            glGenTextures(1, textures, 0);
            checkGlError();

            int texture = textures[0];
            glBindTexture(GL_TEXTURE_2D, texture);
            checkGlError();
            
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource);

            GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
            checkGlError();

            bitmap.recycle();

            return texture;
        }
        
        private int buildProgram(String vertex, String fragment) {
            int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
            if (vertexShader == 0) return 0;

            int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
            if (fragmentShader == 0) return 0;

            int program = glCreateProgram();
            glAttachShader(program, vertexShader);
            checkGlError();

            glAttachShader(program, fragmentShader);
            checkGlError();

            glLinkProgram(program);
            checkGlError();

            int[] status = new int[1];
            glGetProgramiv(program, GL_LINK_STATUS, status, 0);
            if (status[0] != GL_TRUE) {
                String error = glGetProgramInfoLog(program);
                Log.d(LOG_TAG, "Error while linking program:\n" + error);
                glDeleteShader(vertexShader);
                glDeleteShader(fragmentShader);
                glDeleteProgram(program);
                return 0;
            }

            return program;
        }
        
        private int buildShader(String source, int type) {
            int shader = glCreateShader(type);

            glShaderSource(shader, source);
            checkGlError();

            glCompileShader(shader);
            checkGlError();

            int[] status = new int[1];
            glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
            if (status[0] != GL_TRUE) {
                String error = glGetShaderInfoLog(shader);
                Log.d(LOG_TAG, "Error while compiling shader:\n" + error);
                glDeleteShader(shader);
                return 0;
            }
            
            return shader;
        }

        private void checkEglError() {
            int error = mEgl.eglGetError();
            if (error != EGL10.EGL_SUCCESS) {
@@ -152,8 +311,8 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa
        }

        private void checkGlError() {
            int error = GLES20.glGetError();
            if (error != GLES20.GL_NO_ERROR) {
            int error = glGetError();
            if (error != GL_NO_ERROR) {
                Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
            }
        }