javaopenglshaderlwjglvertex-buffer-objects

LWJGL Cannot use offsets when Array Buffer Object is disabled


I have looked at a lot of posts, and cannot find what is wrong with my code. I have bound my VBO however it doesn't work and gives me this error:

Exception in thread "main" org.lwjgl.opengl.OpenGLException: Cannot use
offsets when Array Buffer Object is disabled
at org.lwjgl.opengl.GLChecks.ensureArrayVBOenabled(GLChecks.java:77)
at org.lwjgl.opengl.GL20.glVertexAttribPointer(GL20.java:892)
at glsl.Main.main(Main.java:117)

I don't understand what is wrong here. I have looked everywhere and can't work out what is wrong with this. I have tried it with and without glEnable(GL_ARRAY_BUFFER_BINDING);

package glsl;

import java.nio.FloatBuffer;
import java.util.Scanner;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.*;

import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;

public class Main
{
    private static int initShaderProgram()
    {
        int shaderProgram = glCreateProgram();

        int vertexShader = getShader(GL_VERTEX_SHADER, "/shader.vert");
        glAttachShader(shaderProgram, vertexShader);

        int fragmentShader = getShader(GL_FRAGMENT_SHADER, "/shader.frag");
        glAttachShader(shaderProgram, fragmentShader);

        glLinkProgram(shaderProgram);
        checkError(shaderProgram, GL_LINK_STATUS, true);
        glValidateProgram(shaderProgram);
        checkError(shaderProgram, GL_VALIDATE_STATUS, true);

        return shaderProgram;
    }

    private static int getShader(int shaderType, String shaderName)
    {
        int shader = glCreateShader(shaderType);

        String shaderText = "";
        Scanner scan = new Scanner(Main.class.getResourceAsStream(shaderName));
        while(scan.hasNextLine())
            shaderText = shaderText.concat(scan.nextLine().concat("\n"));
        scan.close();

        System.out.println("\n");
        System.out.println(shaderName+" source: --------------------------------------------");
        System.out.println("\n"+shaderText);
        System.out.println("\n");

        glShaderSource(shader, shaderText);
        glCompileShader(shader);

        checkError(shader, GL_COMPILE_STATUS, false);

        return shader;
    }

    private static void checkError(int shader, int status, boolean isProgram)
    {
        if(!isProgram)
        {
            if(glGetShaderi(shader, status) == org.lwjgl.opengl.GL11.GL_FALSE)
            {
                System.err.println("Shader broken: " + glGetShaderInfoLog(shader, GL_INFO_LOG_LENGTH));
                System.exit(1);
            }
        }else
        {
            if(glGetProgrami(shader, status) == org.lwjgl.opengl.GL11.GL_FALSE)
            {
                System.err.println("Shader broken: " + glGetProgramInfoLog(shader, GL_INFO_LOG_LENGTH));
                System.exit(1);
            }
        }
    }

    public static void main(String[] args)
    {
        try
        {
            Display.setDisplayMode(new DisplayMode(800, 600));
            Display.create();
        }catch(org.lwjgl.LWJGLException e)
        {
            System.exit(1);
        }

        glEnable(GL_ARRAY_BUFFER_BINDING);

        int shaderProgram = initShaderProgram();

        String attribute_name = "coord2d";
        int attribute_coord2d = glGetAttribLocation(shaderProgram, attribute_name);

        int vboTriangle;
        float[] triangleVerticesArray = 
        {
            -1, -1,
            0, 1f,
            1, -1
        };
        FloatBuffer triangleVertices = (FloatBuffer) BufferUtils.createFloatBuffer(triangleVerticesArray.length).put(triangleVerticesArray).flip();

        vboTriangle = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboTriangle);
        glBufferData(GL_ARRAY_BUFFER, triangleVertices, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        while(!Display.isCloseRequested())
        {
            glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);

            glUseProgram(shaderProgram);

            glEnableVertexAttribArray(attribute_coord2d);
            glBindBuffer(GL_VERTEX_ARRAY, vboTriangle);

            glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, false, 0, 0l);

            glBindBuffer(GL_VERTEX_ARRAY, 0);
            glDisableVertexAttribArray(attribute_coord2d);

            glUseProgram(0);

            Display.update();
            Display.sync(60);
        }

        cleanup(shaderProgram, new int[]{vboTriangle});
    }

    private static void cleanup(int shaderProgram, int[] vbos)
    {
        for(int i = 0; i < vbos.length; i++)
            glDeleteBuffers(vbos[i]);

        glDeleteProgram(shaderProgram);
        Display.destroy();
    }
}

Solution

  • You need to set up the pointers with a VAO, a Vertex Array Object.

    int vaoID = glGenVertexArrays();
    

    Then you need to bind it, and set up the pointers with the VBOs, Vertex Array Objects.

    glBindVertexArray(vaoID);
    glEnableVertexAttribArray(indexLocation);
    
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glVertexAttribPointer(indexLocation, 2, GL_FLOAT, false, 0, 0);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    

    Then everytime you render, bind the VAO, and issue a draw command.

    glBindVertexArray(vaoID);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
    

    Then finally, you need to dispose the VAO object.

    glBindVertexArray(0);
    glDeleteVertexArrays(vaoID);
    

    Hope this helps.