0
\$\begingroup\$

I have followed the official OpenGL ES tutorial to create a working OpenGL-environment. I have been able to do anything I wanted to except for displaying 2D-images. To do so I worked through this tutorial and came up with the following:

Here is my Sprite class:

public class Sprite
{
//Reference to Activity Context
private final Context mActivityContext;

//Added for Textures
private final FloatBuffer mCubeTextureCoordinates;
private int mTextureUniformHandle;
private int mTextureCoordinateHandle;
private final int mTextureCoordinateDataSize = 2;
private int mTextureDataHandle;

private final String vertexShaderCode =
    "attribute vec2 a_TexCoordinate;" +
            "varying vec2 v_TexCoordinate;" +
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            "  gl_Position = vPosition * uMVPMatrix;" +
            "v_TexCoordinate = a_TexCoordinate" +
            "}";

private final String fragmentShaderCode =
    "precision mediump float;" +
            "uniform vec4 vColor;" +
            "uniform sampler2D u_Texture;" +
            "varying vec2 v_TexCoordinate;" +
            "void main() {" +
            "gl_FragColor = (vColor * texture2D(u_Texture, v_TexCoordinate));" +
            "}";

private final int shaderProgram;
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;

// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 2;
static float spriteCoords[] = { -0.5f,  0.5f,   // top left
    -0.5f, -0.5f,   // bottom left
    0.5f, -0.5f,   // bottom right
    0.5f,  0.5f }; //top right

private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; //Order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; //Bytes per vertex

// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

public Sprite(final Context activityContext)
{
    mActivityContext = activityContext;

    //Initialize Vertex Byte Buffer for Shape Coordinates / # of coordinate values * 4 bytes per float
    ByteBuffer bb = ByteBuffer.allocateDirect(spriteCoords.length * 4);
    //Use the Device's Native Byte Order
    bb.order(ByteOrder.nativeOrder());
    //Create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    //Add the coordinates to the FloatBuffer
    vertexBuffer.put(spriteCoords);
    //Set the Buffer to Read the first coordinate
    vertexBuffer.position(0);

    // S, T (or X, Y)
    // Texture coordinate data.
    // Because images have a Y axis pointing downward (values increase as you move down the image) while
// OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
// What's more is that the texture coordinates are the same for every face.
final float[] cubeTextureCoordinateData =
        {
            -0.5f,  0.5f,
            -0.5f, -0.5f,
            0.5f, -0.5f,
            0.5f,  0.5f
        };

mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);

//Initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);

int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);

//Texture Code
GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");

GLES20.glLinkProgram(shaderProgram);

//Load the texture
mTextureDataHandle = loadTexture(mActivityContext, R.drawable.ic_launcher);
}

public void draw(float[] mvpMatrix)
{
//Add program to OpenGL ES Environment
GLES20.glUseProgram(shaderProgram);

//Get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");

//Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);

//Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

//Get Handle to Fragment Shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(shaderProgram, "vColor");

//Set the Color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);

//Set Texture Handles and bind Texture
mTextureUniformHandle = GLES20.glGetUniformLocation(shaderProgram, "u_Texture");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");

//Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

//Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);

//Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);

//Pass in the texture coordinate information
mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

//Get Handle to Shape's Transformation Matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");

//Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

//Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

//Disable Vertex Array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}

public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];

GLES20.glGenTextures(1, textureHandle, 0);

if (textureHandle[0] != 0)
{
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;   // No pre-scaling

    // Read in the resource
    final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

    // Bind to the texture in OpenGL
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

    // Set filtering
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

    // Load the bitmap into the bound texture.
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    // Recycle the bitmap, since its data has been loaded into OpenGL.
    bitmap.recycle();
}

if (textureHandle[0] == 0)
{
    throw new RuntimeException("Error loading texture.");
}

return textureHandle[0];
}
}

Here is MyGLRenderer.java:

public class MyGLRenderer implements GLSurfaceView.Renderer {

private static final String TAG = "MyGLRenderer";
private Context context;

private Sprite sprite;

// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];

public MyGLRenderer(Context ctx) {
    this.context = ctx;
}

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {

    // Set the background frame color
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

   sprite = new Sprite(context);
}


@Override
public void onDrawFrame(GL10 unused) {
    sprite.draw(mMVPMatrix);
}

@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
    // Adjust the viewport based on geometry changes,
    // such as screen rotation
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 7);

}

public static int loadShader(int type, String shaderCode){

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

public static void checkGlError(String glOperation) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
        Log.e(TAG, glOperation + ": glError " + error);
        throw new RuntimeException(glOperation + ": glError " + error);
    }
}




//NEW
public static int loadTexture(final Context context, final int resourceId)
{
    final int[] textureHandle = new int[1];

    GLES20.glGenTextures(1, textureHandle, 0);

    if (textureHandle[0] != 0)
    {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;   // No pre-scaling

    // Read in the resource
    final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

    // Bind to the texture in OpenGL
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

    // Set filtering
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

    // Load the bitmap into the bound texture.
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    // Recycle the bitmap, since its data has been loaded into OpenGL.
    bitmap.recycle();
}

if (textureHandle[0] == 0)
{
    throw new RuntimeException("Error loading texture.");
}

return textureHandle[0];
}

The problem that I have is that the app crashes with a

java.lang.RuntimeException: glGetUniformLocation: glError 1282

before it even opens. Thanks for any help in advance!

EDIT: I don't know if this helps but when I start my app in an AVD I get following error:

../../sdk/emulator/opengl//host/libs/Translator/GLES_V2//GLESv2Imp.cpp:glGetAttribLocation:857 error 0x502
../../sdk/emulator/opengl//host/libs/Translator/GLES_V2//GLESv2Imp.cpp:glGetUniformLocation:1442 error 0x502
../../sdk/emulator/opengl//host/libs/Translator/GLES_V2//GLESv2Imp.cpp:glGetUniformLocation:1442 error 0x502
../../sdk/emulator/opengl//host/libs/Translator/GLES_V2//GLESv2Imp.cpp:glGetAttribLocation:857 error 0x502
../../sdk/emulator/opengl//host/libs/Translator/GLES_V2//GLESv2Imp.cpp:glGetUniformLocation:1442 error 0x502
\$\endgroup\$
0
\$\begingroup\$

Lacking an OpenGL compiler I forgot a semicolon. So this

"v_TexCoordinate = a_TexCoordinate" +

should be this:

"v_TexCoordinate = a_TexCoordinate;" +
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.