Hi guys.
I am trying to set up a simple demo application with OpenGL ES 3 on Android and testing with my new Android device. For now, I just want to draw a simple line and can’t figure out what the heck I am missing.
Here my code for the activity:
package de.banaworks.shiftingpillars;
import static android.opengl.GLES10.glDrawArrays;
import static android.opengl.GLES10.glViewport;
import static android.opengl.GLES11.GL_ARRAY_BUFFER;
import static android.opengl.GLES11.GL_STATIC_DRAW;
import static android.opengl.GLES11.glBindBuffer;
import static android.opengl.GLES11.glBufferData;
import static android.opengl.GLES11.glGenBuffers;
import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_LINES;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glDisableVertexAttribArray;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetProgramInfoLog;
import static android.opengl.GLES20.glGetShaderInfoLog;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer;
import static android.opengl.GLES30.GL_MAP_WRITE_BIT;
import static android.opengl.GLES30.glMapBufferRange;
import static android.opengl.GLES30.glUnmapBuffer;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class GameActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final var view = new GLSurfaceView(this) {
};
view.setEGLContextClientVersion(3);
view.setRenderer(new Renderer() {
private final int vertexSize = 4 * 4;
private final int vertexCount = 2;
private final int bufferSize = vertexCount * vertexSize;
private int triangle;
private int shaderProgram;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
loadTriangle();
loadShaderProgram();
}
private void loadTriangle() {
triangle = createBuffer();
glBindBuffer(GL_ARRAY_BUFFER, triangle);
glBufferData(GL_ARRAY_BUFFER, bufferSize, null, GL_STATIC_DRAW);
writeTriangleToArrayBuffer();
}
private int createBuffer() {
final var buffers = new int[1];
glGenBuffers(1, buffers, 0);
return buffers[0];
}
private void writeTriangleToArrayBuffer() {
final var buffer = (ByteBuffer) glMapBufferRange(GL_ARRAY_BUFFER, 0, bufferSize, GL_MAP_WRITE_BIT);
putVertex(1.0f, 0.0f, 0.0f, 1.0f, buffer);
putVertex(-1.0f, 0.0f, 0.0f, 1.0f, buffer);
glUnmapBuffer(GL_ARRAY_BUFFER);
}
private void putVertex(float x, float y, float z, float w, ByteBuffer buffer) {
buffer.putFloat(x).putFloat(y).putFloat(z).putFloat(w);
}
private void loadShaderProgram() {
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, loadShader(GL_VERTEX_SHADER, R.raw.vertex_shader));
glAttachShader(shaderProgram, loadShader(GL_FRAGMENT_SHADER, R.raw.fragment_shader));
glLinkProgram(shaderProgram);
checkShaderProgramState();
}
private int loadShader(int type, int file) {
final var shader = glCreateShader(type);
final var code = new String(loadResource(file));
glShaderSource(shader, code);
glCompileShader(shader);
checkShaderState(shader, code);
return shader;
}
private byte[] loadResource(int file) {
try (final var input = getResources().openRawResource(file)) {
return input.readAllBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void checkShaderState(int shader, String code) {
final var error = glGetShaderInfoLog(shader);
if (error == null) {
throw new RuntimeException(String.format("Compiling shader code:%n%s%nproduced error:%n%s", code, error));
}
}
private void checkShaderProgramState() {
final var error = glGetProgramInfoLog(shaderProgram);
if (error != null && !error.isEmpty()) {
throw new RuntimeException("Linking shader program produced error: " + error);
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
final var positionHandle = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(positionHandle);
glVertexAttribPointer(positionHandle, 4, GL_FLOAT, false, vertexSize, 0);
glDrawArrays(GL_LINES, 0, vertexCount);
glDisableVertexAttribArray(0);
glUseProgram(0);
}
});
setContentView(view);
}
}
Here my two shaders:
attribute vec4 position;
void main() {
gl_Position = position;
}
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
The black screen works but I see no line. What am I missing? I am not entirely sure if I configured the OpenGL ES versions correctly. Also I am not entirely sure if the binding between buffer and shader variable is proper. Any help appreciated!