Search code examples
opengllwjgljogl

OpenGL/JOGL throwing GL_INVALID_OPERATION


I am coding a level editor for a game I am developing. I use JOGL and I seem to have a problem. I am used to LWJGL openGL calls and adjusting to core opengl is a little confusing since lwjgl seem to have simplified a lot of stuff.

So my problem is that I created a model that holds vao ID/name and vertex count and a model loader that creates the model and a renderer. The renderer is not a batched at the moment. I will work on it later. The problem is that opengl throws a GL_INVALID_OPERATION error. Not sure what is causing it. Everything else including the basic triangle I drew to test the environment works, so there seems to be a problem somewhere in my loader or renderer.

Here's the code: Model:

public class JoglModel {
private int vaoID;
private int vertexCount;

public JoglModel(int vertexCount, int vaoID) {
    this.vertexCount = vertexCount;
    this.vaoID = vaoID;
}

public int getVertexCount() {
    return vertexCount;
}

public int getVaoID() {
    return vaoID;
}

}

Loader:

public class ModelLoader {
private  GL2 gl;
private List<int[]> vaos = new ArrayList<int[]>();
private List<int[]> vbos = new ArrayList<int[]>();

public ModelLoader(GL2 gl){
    this.gl = gl;
}

public JoglModel loadToVao(float[] positions){
    int vaoID = createVAO();
    storeDataInAttributeList(0,positions);
    unbind();


    return new JoglModel(vaoID,positions.length/3);
}

private int createVAO(){
    int[] vaoID = new int[1];
    gl.glGenVertexArrays(vaoID.length, vaoID, 0);
    vaos.add(vaoID);
    gl.glBindVertexArray(vaoID[0]);
    return vaoID[0];
}

private void storeDataInAttributeList(int attributeNumber,float[] data){
    int[] vboID = new int[1];
    gl.glGenBuffers(vboID.length,vboID,0);
    vbos.add(vboID);
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER,vboID[0]);
    FloatBuffer floatBuffer = createFloatBuffer(data);
    gl.glBufferData(gl.GL_ARRAY_BUFFER,floatBuffer.remaining(),floatBuffer,gl.GL_STATIC_DRAW);
    gl.glVertexAttribPointer(attributeNumber,3,gl.GL_FLOAT,false,0,0);
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER,0);

}

private FloatBuffer createFloatBuffer(float[] data){
    FloatBuffer floatBuffer = FloatBuffer.allocate(data.length);
    floatBuffer.put(data);
    floatBuffer.flip();
    return floatBuffer;
}

private void unbind(){}
public void clear(){
    for(int[] vao : vaos){
        gl.glDeleteVertexArrays(vao.length,vao,0);
    }

    for(int[] vbo: vbos){
        gl.glDeleteBuffers(vbo.length,vbo,0);
    }
    vaos.clear();
    vbos.clear();
}

}

Renderer:

public class JoglRenderer {

private GL2 gl;

public JoglRenderer(GL2 gl){
    this.gl = gl;
}

public void begin(){
   gl.glClearColor(1f,0f,0f,1f);
   gl.glClear(gl.GL_CLEAR_BUFFER);


}

public void render(JoglModel joglModel){

    gl.glBindVertexArray(joglModel.getVaoID());
    gl.glEnableVertexAttribArray(0);
    gl.glDrawArrays(gl.GL_TRIANGLES,0,joglModel.getVertexCount());
    gl.glDisableVertexAttribArray(0);
    gl.glBindVertexArray(0);

    /*
       gl.glBegin(gl.GL_TRIANGLES);
      gl.glColor3f(1, 0, 0);
       gl.glVertex2f(-1, -1);
      gl.glColor3f(0, 1, 0);
      gl.glVertex2f(0, 1);
      gl.glColor3f(0, 0, 1);
      gl.glVertex2f(1, -1);
     gl.glEnd();
    */
}

public void checkError() {
    String errorString = "";
    int error = gl.glGetError();
    if (error != GL.GL_NO_ERROR) {

        switch (error) {
            case GL.GL_INVALID_ENUM:
                errorString = "GL_INVALID_ENUM";
                break;
            case GL.GL_INVALID_VALUE:
                errorString = "GL_INVALID_VALUE";
                break;
            case GL.GL_INVALID_OPERATION:
                errorString = "GL_INVALID_OPERATION";
                break;
            case GL.GL_INVALID_FRAMEBUFFER_OPERATION:
                errorString = "GL_INVALID_FRAMEBUFFER_OPERATION";
                break;
            case GL.GL_OUT_OF_MEMORY:
                errorString = "GL_OUT_OF_MEMORY";
                break;
            default:
                errorString = "UNKNOWN";
                break;
        }

    }
    System.out.println(errorString);
}

}

the commented out triangle part works just fine. There also seems to be an error in clear screen method but that's not my concern right now. Can any one point out where the problem could be?

Thanks

(EDIT) So i figured out the opengl error. I was accidentally passing the vaoID as the vertex count and vice versa . so i fixed that the error is gone. But nothing is being rendered. Any ideas?


Solution

  • I write here few considerations, since comments are too short for that:

    • loadToVao could lead you wrong, you don't load anything to a vao, the vao is useful to remember which vertices attributes arrays are enabled, their layout/format and which vbo they refer to, so that you don't have to call them every frame. It can also store the bound element array. So glEnableVertexAttribArray and glDisableVertexAttribArray shouldn't go in the render() function

    • the renderer should always be there as default, so I'd suggest to have a main and there initialize your renderer (the GLEventListener)

    • I'd not bind the vao in the createVAO

    • Do not store the GL element. Keep it transient (pass as argument everytime) or get from GLContext. The first option may increase complexity (since every gl call need to have the GL object from the class implementing GLEventListener) but simplifies debugging (because you do know exactly in which order the gl calls get executed).

    • if you need just one vao, avoid creating a List for that, same for the vbo.

    • I suggest you to use static final int variables to hold the vertices attribute indices. It improves readability and avoid potential bugs.

    • Unless you do not need direct buffers, Use GLBuffers to allocate (direct) buffers.

    • What is that gl.GL_FLOAT? I never saw that. Use Float.BYTES or GLBuffers.SIZEOF_FLOAT instead.

    • As @BDL already said, look at glClear and call checkError like here, passing every time a different string so that you can easily find out which is the problematic call if something throw an error.

    • Jogl does have a GL_COLOR_BUFFER_BIT, just write it and call for auto completition, your IDE should suggest you the right location or automatically insert the right import if you set it up properly

    • What it looks also missing (maybe you didn't report it) is glVertexAttribPointer

    • If still it does not work, come back to the basic test triangle, be sure it works and then start building up from there. Move it outside the renderer in its own class, rich it with more geometry, use indexed drawing, ecc. Each step control it works, if it doesn't, then the error lies in your last modifications.