All, Having difficulty with glGenVertexArrays(). I get the following error:
Exception in thread "main" java.lang.IllegalStateException: This functionality is not available. at org.lwjgl.system.Checks.checkFunctionality(Checks.java:57) at org.lwjgl.opengl.GL30.getInstance(GL30.java:667) at org.lwjgl.opengl.GL30.getInstance(GL30.java:662) at org.lwjgl.opengl.GL30.nglGenVertexArrays(GL30.java:2789) at org.lwjgl.opengl.GL30.glGenVertexArrays(GL30.java:2816) at renderEngine.Loader.createVAO(Loader.java:26) at renderEngine.Loader.loadToVAO(Loader.java:19) at renderEngine.MainGameLoop.main(MainGameLoop.java:27)
Here is my Main Game Loop (I call GL.createCapabilities() from the createDisplay() method.)
package renderEngine;
import static org.lwjgl.glfw.GLFW.*;
public class MainGameLoop {
public static DisplayManager dm = new DisplayManager();
public static void main(String[] args) {
//Create Display
dm.createDisplay();
Loader loader = new Loader();
Renderer renderer = new Renderer();
float[] vertices = {
-0.5f,0.5f,0f,
-0.5f,-0.5f,0f,
0.5f,-0.5f,0f,
0.5f,-0.5f,0f,
0.5f,0.5f,0f,
-0.5f,0.5f,0f
};
RawModel model = loader.loadToVAO(vertices);
//Game Loop
while (glfwWindowShouldClose(dm.getWindowID()) != GLFW_TRUE) {
renderer.prepare();
renderer.render(model);
dm.updateDisplay();
}
//Destroy Display
dm.destroyWindow();
loader.cleanUp();
}
}
As referenced above, here is the Display Manager class:
package renderEngine;
import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.opengl.GL;
public class DisplayManager {
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;
private long windowID;
//Constructor
public DisplayManager(){
init();
}
private void init(){
if(glfwInit() != GLFW_TRUE){
throw new IllegalStateException("Unable to initiate GLFW");
}
}
public long createDisplay(){
windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
if(windowID == 0){
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
GLFW.glfwSetWindowTitle(windowID, "GLFW Window");
setErrorCallback();
setKeyCallback();
glfwMakeContextCurrent(windowID);
GL.createCapabilities();
return windowID;
}
public long getWindowID(){
return this.windowID;
}
private void setErrorCallback(){
errorCallback = GLFWErrorCallback.createPrint(System.err);
glfwSetErrorCallback(errorCallback);
}
private void setKeyCallback(){
keyCallback = new GLFWKeyCallback(){
@Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
}
};
glfwSetKeyCallback(windowID, keyCallback);
}
public void updateDisplay(){
GLFW.glfwSwapInterval(1);
glfwSwapBuffers(windowID);
glfwPollEvents();
}
public void destroyWindow(){
glfwDestroyWindow(windowID);
keyCallback.release();
glfwTerminate();
errorCallback.release();
}
}
If would seem the above mentioned error is with the loader class:
package renderEngine;
import java.util.List;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Loader {
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
public RawModel loadToVAO(float[] positions){
int vaoID = createVAO();
storeDataInAttributeList(0,positions);
unbindVAO();
return new RawModel(vaoID,positions.length/3);
}
private int createVAO() {
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
private void storeDataInAttributeList(int attributeNumber, float[] data) {
int vboID = GL15.glGenBuffers();
vbos.add(vboID);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
FloatBuffer buffer = storeDataInFloatBuffer(data);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}
private void unbindVAO() {
GL30.glBindVertexArray(0); //0 un-binds currently bound VAO
}
public void cleanUp(){
for(int vao:vaos){
GL30.glDeleteVertexArrays(vao);
}
for(int vbo:vbos){
GL15.glDeleteBuffers(vbo);
}
}
private FloatBuffer storeDataInFloatBuffer(float[] data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}
In Particular this line of code:
GL30.glBindVertexArray(vaoID);
As far as I can see this is the correct method to do it, and the GL capabilities/context have been set/called from the main thread (main game loops main method, utilising the display manager)
For completeness, here are the RawModel and Renderer Classes, do not suspect an issue these these:
package renderEngine;
public class RawModel {
private int vaoID;
private int vertexCount;
public RawModel(int vaoID, int vertexCount){
this.vaoID = vaoID;
this.vertexCount = vertexCount;
}
public int getVaoID() {
return vaoID;
}
public int getVertexCount() {
return vertexCount;
}
}
And here is the Renderer Class:
package renderEngine;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Renderer {
public void prepare(){
GL11.glClearColor(1, 0, 0, 1);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
}
public void render(RawModel model){
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
}
Any assistance you can give me regarding my implementation of 'glGenVertexArrays' would be much appreciated.
I have now added the following
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
However, am now getting the following error:
Exception in thread "main" java.lang.RuntimeException: Failed to create the GLFW window at renderEngine.DisplayManager.createDisplay(DisplayManager.java:37) at renderEngine.MainGameLoop.main(MainGameLoop.java:12)
The specific implementation of my createDisplay() is as follows:
public long createDisplay(){
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
if(windowID == 0){
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
GLFW.glfwSetWindowTitle(windowID, "GLFW Window");
setErrorCallback();
setKeyCallback();
glfwMakeContextCurrent(windowID);
GL.createCapabilities();
return windowID;
}
UPDATE
If have removed the error callbacks, as thought they might be causing an issue. The resulting error is:
Exception in thread "main" java.lang.RuntimeException: Failed to create the GLFW window at renderEngine.DisplayManager.createDisplay(DisplayManager.java:40) at renderEngine.MainGameLoop.main(MainGameLoop.java:12)
It seems the RuntimeException is being thrown, and is displaying my custom error message if the glfw window cannot be created. Could this be todo with the order in which I run this? I have played around with the placement of the 'init' method with noluck. There has got to be something I am overlooking?... Thanks.
Updated code for the Display Manager:
package renderEngine;
import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.opengl.GL;
public class DisplayManager {
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;
private long windowID;
//Constructor
public DisplayManager(){
init();
}
private void init(){
if(glfwInit() != GLFW_TRUE){
throw new IllegalStateException("Unable to initiate GLFW");
}
}
public long createDisplay(){
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
System.out.println(windowID);
if(windowID == 0){
glfwTerminate();
throw new RuntimeException("Failed to create the GLFW window");
}
glfwMakeContextCurrent(windowID);
GL.createCapabilities();
GLFW.glfwSetWindowTitle(windowID, "GLFW Window");
//setErrorCallback();
//setKeyCallback();
return windowID;
}
public long getWindowID(){
return this.windowID;
}
private void setErrorCallback(){
errorCallback = GLFWErrorCallback.createPrint(System.err);
glfwSetErrorCallback(errorCallback);
}
private void setKeyCallback(){
keyCallback = new GLFWKeyCallback(){
@Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
}
};
glfwSetKeyCallback(windowID, keyCallback);
}
public void updateDisplay(){
GLFW.glfwSwapInterval(1);
glfwSwapBuffers(windowID);
glfwPollEvents();
}
public void destroyWindow(){
glfwDestroyWindow(windowID);
keyCallback.release();
glfwTerminate();
errorCallback.release();
}
}
Many Thanks and Kind Regards, Jake
The
glGenVertexArrays
function requires OpenGL 3.0 or higher. You have to explicitly tell GLFW this. Before callingglfwCreateWindow
:You can check that you have OpenGL 3.0 or higher by calling
GL11.glGetString(GL11.GL_VERSION)
or by looking at theGL.getCapabilities().OpenGL30
flag.