I am migrating an app that draws on OpenGL ES 1.0 to OpenGL ES 2.0.
The app used to draw multiple 2D triangles, as a vertex array, where the vertices matched the pixels on screen.
I made a sample project to reproduce the problem.
The data
static ShortBuffer provideData() {
final ByteBuffer data = ByteBuffer.allocateDirect(12 * BYTES_PER_SHORT);
data.order(ByteOrder.nativeOrder());
final ShortBuffer floatData = data.asShortBuffer();
floatData.put(new short[]{
351, 22, 361, 22, 361, 32, 351, 22, 351, 32, 361, 32
});
return floatData;
}
OpenGL 1.0: works as expected:
final class FirstGenRenderer implements GLSurfaceView.Renderer {
private static final int VERTICES_PER_PARTICLE = 6;
private final ShortBuffer coordinates = DataProvider.provideData();
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
final int color = Color.DKGRAY;
gl.glClearColor(
Color.red(color) / 255f,
Color.green(color) / 255f,
Color.blue(color) / 255f, 0f);
final int particleColor = Color.WHITE;
gl.glColor4f(
Color.red(particleColor) / 255f,
Color.green(particleColor) / 255f,
Color.blue(particleColor) / 255f, 0f);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glOrthof(0, width, 0, height, 1, -1);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
coordinates.position(0);
gl.glVertexPointer(2, GL10.GL_SHORT, 0, coordinates);
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, VERTICES_PER_PARTICLE);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
The output: clear color and a small white square at the bottom
The same implementation on GL 2.0: does not produce desired results:
package com.doctoror.ortho;
import android.graphics.Color;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.support.annotation.NonNull;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public final class SecondGenRenderer implements GLSurfaceView.Renderer {
private static final int COORDINATES_PER_VERTEX = 2;
private static final int VERTICES_PER_PARTICLE = 6;
private static final String VERTEX_SHADER_CODE =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private static final String FRAGMENT_SHADER_CODE =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final ShortBuffer coordinates = DataProvider.provideData();
private final float[] mvpMatrix = new float[16];
private final float[] projectionMatrix = new float[16];
private final float[] viewMatrix = new float[16];
private int program;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
final int vertexShader = loadShader(
GLES20.GL_VERTEX_SHADER,
VERTEX_SHADER_CODE);
final int fragmentShader = loadShader(
GLES20.GL_FRAGMENT_SHADER,
FRAGMENT_SHADER_CODE);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
final int color = Color.DKGRAY;
GLES20.glClearColor(
Color.red(color) / 255f,
Color.green(color) / 255f,
Color.blue(color) / 255f, 0f);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
Matrix.orthoM(projectionMatrix, 0, 0f, width, 0f, height, 1, -1);
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f);
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glUseProgram(program);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
final int positionHandle = GLES20.glGetAttribLocation(program, "vPosition");
checkGlError("glGetAttribLocation");
GLES20.glEnableVertexAttribArray(positionHandle);
checkGlError("glEnableVertexAttribArray");
coordinates.position(0);
GLES20.glVertexAttribPointer(
positionHandle,
COORDINATES_PER_VERTEX,
GLES20.GL_FLOAT,
false,
0,
coordinates);
checkGlError("glVertexAttribPointer");
final int colorHandle = GLES20.glGetUniformLocation(program, "vColor");
checkGlError("glGetUniformLocation");
final float[] color = new float[]{1f, 1f, 1f, 1f};
GLES20.glUniform4fv(colorHandle, 1, color, 0);
final int mvpMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
checkGlError("glGetUniformLocation");
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);
checkGlError("glUniformMatrix4fv");
GLES20.glDrawArrays(GL10.GL_TRIANGLES, 0, VERTICES_PER_PARTICLE);
checkGlError("glDrawArrays");
GLES20.glDisableVertexAttribArray(positionHandle);
}
private static int loadShader(final int type, @NonNull final String shaderCode) {
final int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
private static void checkGlError(@NonNull final String glOperation) {
int error;
if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
The output: a clear color.
Expected output: as with GLES10, above.