Section: OpenGL ES 2.0 with libGDX

LibGDX is built on top of OpenGL 2.0. They dropped support for 1.x in March 2014. There is some support for 3.0 but the most widely used version is 2.0 as of this writing, May 2015, so that's what I'll focus on. My source for OpenGL commands and their usage is the official wiki. Using a combination of articles, blogs and books (check out the "Useful Reading" link in the sidebar) I present the following code for rendering three, perspective projected points to the screen using raw Java and OpenGL.

MainActivity.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class MainActivity extends Activity{
    private GLSurfaceView surfaceView;

    @Override
    protected void onCreate( Bundle savedInstanceState ){
        super.onCreate( savedInstanceState );
        surfaceView = new GLSurfaceView( this );
        surfaceView.setEGLContextClientVersion( 2 );
        surfaceView.setRenderer( new GLES20Renderer() );
        setContentView( surfaceView );
    }
}

Renderer.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.Matrix;

public class Renderer implements Renderer{
    private int shaderProgram;
    private int positionVariableLocation;
    private int uMVPVariableLocation;
    private FloatBuffer fBuffer;

    private float[] viewMatrix = new float[ 16 ];
    private float[] projectionMatrix = new float[ 16 ];
    private float[] MVPMatrix = new float[ 16 ];

    public void onSurfaceCreated( GL10 gl, EGLConfig config ){
        GLES20.glClearColor( 0.0f, 0.0f, 0.0f, 1 );
    }

    public void onSurfaceChanged( GL10 gl, int width, int height ){
        GLES20.glViewport( 0, 0, width, height );

        float[] vertices = {
                0, 0, 2,  // Vertex 1 (x, y, z)
                0, 1, -3, // Vertex 2 (x, y, z)
                -2, 2, 0  // Vertex 3 (x, y, z)
        };

        ByteBuffer verticesBB = ByteBuffer.allocateDirect( vertices.length * 4 );
        verticesBB.order( ByteOrder.nativeOrder() );
        fBuffer = verticesBB.asFloatBuffer();
        fBuffer.put( vertices );
        fBuffer.position( 0 );

        float ratio = (float) width / height;
        float zNear = 0.1f;
        float zFar = 1000;
        float fov = 0.75f; // 0.2 to 1.0
        float size = (float)( zNear * Math.tan(fov / 2) );
        Matrix.setLookAtM( viewMatrix, 0, -13, 5, 10, 0, 0, 0, 0, 1, 0);
        Matrix.frustumM( projectionMatrix, 0, -size, size, -size / ratio, size / ratio, zNear, zFar );
        Matrix.multiplyMM( MVPMatrix, 0, projectionMatrix, 0, viewMatrix, 0 );

        int vertexShader = loadShader( GLES20.GL_VERTEX_SHADER, vertexShaderCode );
        int fragmentShader = loadShader( GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode );
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader( shaderProgram, vertexShader );
        GLES20.glAttachShader( shaderProgram, fragmentShader );
        GLES20.glLinkProgram( shaderProgram );

        positionVariableLocation = GLES20.glGetAttribLocation( shaderProgram, "position" );
        uMVPVariableLocation = GLES20.glGetUniformLocation( shaderProgram, "uMVP" );
    }

    public void onDrawFrame( GL10 gl ){
        GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT );

        GLES20.glUseProgram( shaderProgram );
        GLES20.glUniformMatrix4fv( uMVPVariableLocation, 1, false, MVPMatrix, 0 );
        GLES20.glVertexAttribPointer( positionVariableLocation, 3, GLES20.GL_FLOAT, false, 0, fBuffer );
        GLES20.glEnableVertexAttribArray( positionVariableLocation );
        GLES20.glDrawArrays( GLES20.GL_POINTS, 0, 3 );
    }

    private int loadShader( int type, String source ){
        int shader = GLES20.glCreateShader( type );
        GLES20.glShaderSource( shader, source );
        GLES20.glCompileShader( shader );
        return shader;
    }

    private final String vertexShaderCode =
            "attribute vec3 position;            \n"
        + "uniform mat4 uMVP;                    \n"
        + "void main() {                         \n"
        + " vec4 vertex = vec4( position, 1.0 ); \n"
        + " gl_Position = uMVP * vertex;         \n"
        +   " gl_PointSize = 15.0;               \n"
        + "}                                     \n";

    private final String fragmentShaderCode =
            "#ifdef GL_FRAGMENT_PRECISION_HIGH  \n"
        + "precision highp float;               \n"
        + "#else                                \n"
        + "precision mediump float;             \n"
        + "#endif                               \n"
        + "void main() {                        \n"
        + " gl_FragColor = vec4( 1.0 );         \n"
        + "}                                    \n";

}

Running the above code will produce the following output:

Now that we've seen the code and what it does, it's time to tear it apart and see how libGDX abstracts it away.

Next.