0

I am trying to use an array of floats for my verticies in OpenGLES 2.0 on Android instead of a FloatBuffer but When I do I glDrawArrays gives the error 0x502 or GL_INVALID_OPERATION.

I do not get this error and everything works fine when I use FloatBuffers.

I have read that this error is normally caused by a program not being set. I only use one shader program and I set it when everything initialized.

Here is my code

public class LineEngine {
    private static final float[] IDENTIY = new float[16];
    private float[] mLinePoints;
    private float[] mLineColors;
    private int mCount;

    public LineEngine(int maxLines) {
        Matrix.setIdentityM(IDENTIY, 0);

        mLinePoints = new float[maxLines * 2 * 4];
        mLineColors = new float[maxLines * 2 * 4];

        reset();
    }

    public void addLine(float[] position, float[] color) {
        int offset = mCount * 2 * 4;
        System.arraycopy(position, 0, mLinePoints, offset, 8);
        System.arraycopy(color, 0, mLineColors, offset, 4);
        System.arraycopy(color, 0, mLineColors, offset + 4, 4);

        mCount++;
    }

    public void reset() {
        mCount = 0;
    }

    public void draw() {
        if (mCount > 0) {
            GraphicsEngine.setMMatrix(IDENTIY);
            GraphicsEngine.setColors(mLineColors);
            GraphicsEngine.setVertices4d(mLinePoints);
            GraphicsEngine.disableTexture();
            GLES20.glDrawArrays(GLES20.GL_LINES, 0, mCount * 2);

            int error = GLES20.glGetError();
            if (error != 0)
                Log.e("OpenGL", "Draw " + error); // Prints error 1282

            GraphicsEngine.disableColors();
            reset();
        }
    }
}

This code works fine with no errors

public class LineEngine {
    private static final float[] IDENTIY = new float[16];
    private FloatBuffer mLinePoints;
    private FloatBuffer mLineColors;
    private int mCount;

    public LineEngine(int maxLines) {
        Matrix.setIdentityM(IDENTIY, 0);

        ByteBuffer byteBuf = ByteBuffer.allocateDirect(maxLines * 2 * 4 * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        mLinePoints = byteBuf.asFloatBuffer();

        byteBuf = ByteBuffer.allocateDirect(maxLines * 2 * 4 * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        mLineColors = byteBuf.asFloatBuffer();

        reset();
    }

    public void addLine(float[] position, float[] color) {
        mLinePoints.put(position, 0, 8);
        mLineColors.put(color, 0, 4);
        mLineColors.put(color, 0, 4);
        mCount++;
    }

    public void reset() {
        mLinePoints.position(0);
        mLineColors.position(0);
        mCount = 0;
    }

    public void draw() {
        if (mCount > 0) {
            mLinePoints.position(0);
            mLineColors.position(0);
            GraphicsEngine.setMMatrix(IDENTIY);
            GraphicsEngine.setColors(mLineColors);
            GraphicsEngine.setVertices4d(mLinePoints);
            GraphicsEngine.disableTexture();
            GLES20.glDrawArrays(GLES20.GL_LINES, 0, mCount * 2);

            int error = GLES20.glGetError();
            if (error != 0)
                Log.e("OpenGL", "Draw " + error); // no errors

            GraphicsEngine.disableColors();
            reset();
        }
    }
}

The related GraphicsEngine code is here

public static void setVertices4d(FloatBuffer vertices) {
    GLES20.glVertexAttribPointer(aVertexHandle, 4, GLES20.GL_FLOAT, false,
            16, vertices);
    GLES20.glEnableVertexAttribArray(aVertexHandle);
    mState.shape = -1;
}

public static void setVertices4d(float[] vertices) {
    GLES20.glVertexAttrib4fv(aVertexHandle, vertices, 0);
    GLES20.glEnableVertexAttribArray(aVertexHandle);
    mState.shape = -1;
}

public static void setColors(FloatBuffer colors){
    GLES20.glVertexAttribPointer(aColor, 4, GLES20.GL_FLOAT, false,
            16, colors);
    GLES20.glEnableVertexAttribArray(aColor);
    GLES20.glUniform1i(GraphicsEngine.uEnableColors, 1);
}

public static void setColors(float[] colors){
    GLES20.glVertexAttrib4fv(aColor, colors, 0);
    GLES20.glEnableVertexAttribArray(aColor);
    GLES20.glUniform1i(GraphicsEngine.uEnableColors, 1);
}

I don't want to use FloatBuffers because they are slower to change than an array of floats.

Alchitry
  • 1,369
  • 1
  • 16
  • 29

1 Answers1

3

You don't have a choice but to use FloatBuffers for this code.

Your setVertices4d method which takes a float[] is broken, you cannot use glVertexAttrib4fv in that way. glVertexAttrib4 only specifies a single vertex, and using the v version just passes the values of an attribute as an array to that single vertex, it doesn't set up a vertex array similar to the pointer functions.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
Tim
  • 35,413
  • 11
  • 95
  • 121
  • You can use glUniform4fv to pass in a float[] with a length more than 1 for uniforms though right? I'm doing that in another section of my code and it's working. Is it something unique about vertex attributes that makes it so you can't? Looking at http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml it says _Specifies a pointer to an array of values to be used for the generic vertex attribute._ That makes it sound like you can pass in more than one value. – Alchitry May 29 '12 at 06:02
  • 1
    Uniforms and Attributes are totally different. Uniforms are just a single value that's always constant. When you're specifying attributes, you're creating a big list of attributes such that you have one per vertex. glVertexAttrib specifies attributes for a single vertex at a time. If you want to define an array of vertices, then you must use glVertexAttribPointer with the FloatBuffers. – Tim May 29 '12 at 06:06
  • Do you know where I can find any documentation on all of this? – Alchitry May 29 '12 at 06:08
  • Just the sdk/docs which you've found is the only source I know, you'll learn this stuff the more time you spend with it. I can see where you're coming from that you would think that you can specify an array of vertices with that, but it just doesn't work that way. I think you would use the vector form of that function for example if you were doing multitexturing, and you wanted to pass an array of multiple texcoords to each vertex. – Tim May 29 '12 at 06:12
  • `glVertexAttribX` can only set the attribute values for a single vertex **and** a single attribute. So this multitexturing idea won't work that way, too. Any array larger than 4 elements won't make any sense to this function, which is just there if you have your vertex attribute as, say, a vector of 4 values. But of course the overall answer is correct and you (OP) are using this function in the wrong way. Since you (OP) enable the attribute arrays anyway, the values set with `glVertexAttrib` are not used anyway, as they only grip when the respective array is disabled. – Christian Rau May 29 '12 at 08:09
  • Oh yes my bad, for some reason I thought that **4v** meant 4 * number of vectors, not just a pointer to 4 floats. Don't use it very often, my mistake! – Tim May 29 '12 at 08:28