ESColors Renderer

          
package com.vizit;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.microedition.khronos.egl.EGLConfig;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import java.nio.IntBuffer;
import android.util.Log;

/**
 * Render a simple triangle using the simplest possible OpenGL ES 2.
 */
public class TriangleRenderer
             implements GLSurfaceView.Renderer
{
    private final String      appName               = "ESColors";


    /** How many bytes per float. */
    private final int         bytesPerFloat         = 4;
    /** R, G, B, A for color at each vertex. */
    private final int         colorElementSize      = 4;
    /** Number of vertex elements. */
    private final int         nElements             = 3;
    /** Each position element has three values, x,y, and z coordinates. */
    private final int         positionElementSize   = 3;
    /** Offset of the position data. */
    private final int         positionOffset        = 0;
    private       int         program;
    private       float[]     vertices;

    public TriangleRenderer()
    {
        // We can mix other information in with the vertex positions.
        // Here we mix in the color of the vertex. This is a very efficient
        // arrangement.
        vertices = new float[] {
                                 // Vertex coordinate, 3 floats (XYZ)
                                -1.0f, -1.0f, 0.0f,
                                 // Vertex color, four floats (RGBA)
                                 1.0f,  0.0f, 0.0f, 1.0f,
                                 1.0f, -1.0f, 0.0f,
                                 0.0f,  1.0f, 0.0f, 1.0f,
                                 0.0f,  1.0f, 0.0f,
                                 0.0f,  0.0f, 1.0f, 1.0f
                               };
    }

    /**
     * Compile a shader of the given type.
     * @param shaderSource A string containing GLSL code for the shader.
     * @param shaderType   The type of shader: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER for OpenGL ES 2.
     *
     * @return The compiled shader.
     */
    protected int compileShader(String shaderSource, int shaderType)
    {
        IntBuffer logStatus;
        int       shader;
        String    compileLog;
        int[]     compileStatus;

        shader = GLES20.glCreateShader(shaderType);
        // Pass in the shader source.
        GLES20.glShaderSource(shader, shaderSource);
        // Compile the shader.
        GLES20.glCompileShader(shader);

        // Get the compilation status. An int would be passed by value and not modifiable.
        // So wrap in a one element array.
        compileStatus = new int[1];
        // 0 is offset into array to place the status.
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

        // Error compile status, get the relevant log.
        if (compileStatus[0] != GLES20.GL_TRUE)
        {
            logStatus     = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
            GLES20.glGetShaderiv(shader, GLES20.GL_INFO_LOG_LENGTH, logStatus);
            if (logStatus.get(0) > 0)
            {
                compileLog = GLES20.glGetShaderInfoLog(shader);
                Log.d(appName, "Shader compilation failed with, " + compileLog);
            }
            else
            {
                // Workaround for issue 9953, where GL_INFO_LOG_LENGTH is zero.
                Log.d(appName, "Shader compilation failed for an unknown reason.");
            }
            GLES20.glDeleteShader(shader);
            shader = 0;
        }
        
        return shader;
    }

    /**
     * Given the handles to two previously compiled shaders, assemble them into a program.
     *
     * @param vertexShader   The handle for the vertex shader for this program.
     * @param fragmentShader The handle for ths fragment shader for this program.
     *
     * @return int A handle on the linked program.
     */
    protected int createProgram(int vertexShader, int fragmentShader)
    {
        String    loaderLog;
        IntBuffer logStatus;
        int       program;

        program = GLES20.glCreateProgram();

        GLES20.glAttachShader(program, vertexShader);

        // Bind the fragment shader to the program.
        GLES20.glAttachShader(program, fragmentShader);

        GLES20.glLinkProgram(program);

        // Get the link status.
        final int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);

        // If the link failed, delete the program.
        if (linkStatus[0] == 0)
        {
            logStatus     = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
            GLES20.glGetProgramiv(program, GLES20.GL_INFO_LOG_LENGTH, logStatus);
            if (logStatus.get(0) > 0)
            {
                loaderLog = GLES20.glGetProgramInfoLog(program);
                Log.d(appName, "Program linking failed with, " + loaderLog);
            }
            else
            {
                // Workaround for issue 9953, where GL_INFO_LOG_LENGTH is zero.
                Log.d(appName, "Program linking failed for an unknown reason.");
            }
            GLES20.glDeleteProgram(program);
            program = 0;
        }

        GLES20.glUseProgram(program);

        return program;
    }

    /**
     * Invoked after the rendering surface is setup - the OpenGL context is created.
     * It is now safe to compile shaders, build programs, setup vertex buffers, etc.
     */
    @Override
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
    {
        // Both position and color are input for each vertex
        // vColor is a varying, indicating that it is to be supplied
        // to the fragment shader.
        final String vertexShaderSource   = "attribute vec3 position;"
                                            + "attribute vec4 color;"
                                            + ""
                                            + "varying vec4 vColor;"
                                            + ""
                                            + "void main()"
                                            + "{"
                                            + "    gl_Position = vec4(position, 1);"
                                            + "    vColor      = color;"
                                            + "}";

        // The fragment shader can be thought of for now as doing per pixel computations. It is the
        // fragment shader the colors each pixel in a 3d scene. We now have the vColor varying.
        final String fragmentShaderSource = "precision mediump float;"
                                            + ""
                                            + "varying vec4 vColor;"
                                            + ""
                                            + "void main()"
                                            + "{"
                                            + "    gl_FragColor = vColor;"
                                            + "}";

        int vertexShader   = compileShader(vertexShaderSource,   GLES20.GL_VERTEX_SHADER);
        int fragmentShader = compileShader(fragmentShaderSource, GLES20.GL_FRAGMENT_SHADER);

        program = createProgram(vertexShader, fragmentShader);
    }


    /**
     * Height or width changed, usually portrait <=> landscape.
     */
    @Override
    public void onSurfaceChanged(GL10 glUnused, int width, int height)
    {
        // Resize our drawing surface to the new height and width.
        GLES20.glViewport(0, 0, width, height);
    }

    /**
     * Load vertex data into a buffer so that it can be read into vertex shader attributes.
     *
     * @param vertexData An array of floats containing per vertex data.
     */
    protected FloatBuffer createBuffer(float[] vertexData)
    {
        /** Store our model data in a float buffer. */
        FloatBuffer vertexBuffer;

        // The OpenGL Driver expects floating point data in native byte order.
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * bytesPerFloat)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();

        vertexBuffer.put(vertexData).position(0);

        return vertexBuffer;
    }

    /**
     * Setup pointer for attribute to read data into shader attribute.
     * @param vertexBuffer The FloatBuffer within this program space containing the data to be read.
     * @param program      A handle on the GLSL program that will consume the data.
     * @param attribute    A String giving the name of the shader attribute associated with this data.
     * @param size         The number of entries from the buffer that make up each attribute value.
     * @param type         The type of each entry.
     * @param stride       An in giving the begin-begin spacing of values in bytes. 0 for adjacent values.
     * @param offset       An in giving the offset into the FloatBuffer where we begin reading data.
     */
    protected void bindBuffer(FloatBuffer vertexBuffer, int program, String attribute, int size, int type, int stride, int offset)
    {
        int            attributeLocation;
        vertexBuffer.position(offset);

        // Lookup the attribute name.
        attributeLocation = GLES20.glGetAttribLocation(program, attribute);

        // Setup pointer into the FloatBuffer to read the data into the attribute.
        GLES20.glVertexAttribPointer(attributeLocation, size, type, false, stride, vertexBuffer);

        // Enable reading arrays into the attribute.
        GLES20.glEnableVertexAttribArray(attributeLocation);
    }


    /**
     * Draws each frame.
     * @param glUnused
     */
    @Override
    public void onDrawFrame(GL10 glUnused)
    {
        int         stride;
        FloatBuffer vertexBuffer;

        vertexBuffer = createBuffer(vertices);
        // Spacing between beginnings of values for each vertex. Allow for three position and four color words.
        stride       = bytesPerFloat*(colorElementSize + positionElementSize);
        // The position data starts at the beginning of the buffer, and each entry contains three floats.
        bindBuffer(vertexBuffer, program, "position", positionElementSize, GLES20.GL_FLOAT, stride, positionOffset);
        // The color data starts after the position data, and contains four floats.
        bindBuffer(vertexBuffer, program, "color",    colorElementSize,    GLES20.GL_FLOAT, stride, positionOffset + positionElementSize);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, nElements);
    }
}
          
        

Notes

Here, though, we have significant differences.