Whenever i try to populate a VAO, i get a null pointer exception
Error
Hello LWJGL 3.0.0a!
2.1 INTEL-10.0.86
Exception in thread "main" java.lang.NullPointerException
at org.lwjgl.opengl.GL30.nglGenVertexArrays(GL30.java:3265)
at org.lwjgl.opengl.GL30.glGenVertexArrays(GL30.java:3294)
at javaapplication73.Loader.createVAO(Loader.java:35)
at javaapplication73.Loader.loadToVao(Loader.java:27)
at javaapplication73.HelloWorld.initial(HelloWorld.java:139)
at javaapplication73.HelloWorld.loop(HelloWorld.java:120)
at javaapplication73.HelloWorld.run(HelloWorld.java:32)
at javaapplication73.HelloWorld.main(HelloWorld.java:154)
Java Result: 1
The code that throws this exception is the createVAO method in this Loader class.
package javaapplication73;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
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 = this.createVAO();
this.storeDataInAttributeList(0, positions);
this.unbindVAO();
return new RawModel(1, positions.length/3);
}
private int createVAO(){
int vaoID = GL30.glGenVertexArrays();
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
public 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);
}
public void unbindVAO(){
//unbind the array
GL30.glBindVertexArray(0);
}
private FloatBuffer storeDataInFloatBuffer(float[] data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
//need to flip between wright and read
buffer.flip();
return buffer;
}
public void cleanUp(){
for (Integer vao : this.vaos) {
GL30.glDeleteVertexArrays(vao);
}
for(Integer vbo : this.vbos){
GL15.glDeleteBuffers(vbo);
}
}
}
I don't think that this class is really needed, but this is my main class
package javaapplication73;
import org.lwjgl.Sys;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import java.nio.ByteBuffer;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
public class HelloWorld {
// We need to strongly reference callback instances.
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;
// The window handle
private long window;
private final int fpsCap = 120;
Loader loader = new Loader();
Renderer renderer = new Renderer();
private RawModel model;
public void run() {
System.out.println("Hello LWJGL " + Sys.getVersion() + "!");
try {
init();
loop();
// Release window and window callbacks
glfwDestroyWindow(window);
keyCallback.release();
} finally {
// Terminate GLFW and release the GLFWerrorfun
glfwTerminate();
errorCallback.release();
}
}
private void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( glfwInit() != GL11.GL_TRUE )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure our window
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
int WIDTH = 1200;
int HEIGHT = 800;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Not so Still Life", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, GL_TRUE); // We will detect this in our rendering loop
cleanUp();
}
});
// Get the resolution of the primary monitor
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(GLFWvidmode.width(vidmode) - WIDTH) / 2,
(GLFWvidmode.height(vidmode) - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
private void loop() {
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the ContextCapabilities instance and makes the OpenGL
// bindings available for use.
GLContext.createFromCurrent();
// Set the clear color
glClearColor(.3243f,0,.83251234f,0);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
while ( glfwWindowShouldClose(window) == GL_FALSE ) {
// Clear the screen and depth buffer
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
initial();
Render();
glfwSwapBuffers(window); // swap the color buffers
glfwPollEvents();
}
}
public void initial(){
System.out.println(glGetString(GL_VERSION));
//Pre game stuff
float[] verticies = {
-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,
};
model = loader.loadToVao(verticies);
}
public void Render(){
renderer.prepare();
renderer.Render(model);
}
public void cleanUp(){
System.out.println("CleanUp");
this.loader.cleanUp();
}
public static void main(String[] args) {
System.setProperty("org.lwjgl.librarypath", "/Users/Bayjose/LWJGL/lwjgl/native");
new HelloWorld().run();
}
}
The computer that I am codeing this on is a Macbook Pro 2014 model, running osx Yosemite 10.10.1
Dont know if that has anything to do with the error or not
Related
I've been trying to render a triangle on my screen for the past day but I can't figure out what I'm doing incorrectly. The only thing that works is displaying a window and rendering to it using clear color. Does anyone know what I'm doing incorrectly? All I'm expecting is to see a black triangle rendered on screen like I've done once in the past but currently I'm not able to do that.
Here's the code:
Main:
public class Main {
public static void main(String[] args){
System.out.println("Hello");
// Create Window
Window.createWindow();
long window = Window.getWindow();
// Create Renderer
Renderer renderer = new Renderer();
// Data
float[] positions = {
0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
// Create Model
Model triangle = Loader.dataToModel(positions);
// Render on window
while(!GLFW.glfwWindowShouldClose(window)){
GLFW.glfwPollEvents();
renderer.clear();
renderer.render(triangle);
GLFW.glfwSwapBuffers(window); // !##!##!## remember to add!!! !##!## Order important prob
}
System.out.println("TERMINATED");
Window.terminateWindow();
}
}
Window:
public class Window {
private static long window;
private static Callback debugCallback;
public static void createWindow(){
// Creates a window
// Init
if(!GLFW.glfwInit()){
throw new IllegalStateException("ERROR: could not GLFW.glfwInit()");
}
// Hints
// Hint opengl version
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR,3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR,2);
// Hint compatibility (profile, forward compat)
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE,GLFW.GLFW_OPENGL_CORE_PROFILE);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT,GLFW.GLFW_TRUE);
// Hint to hide initially
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE,GLFW.GLFW_FALSE);
// Hint debug
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE);
// Actually create window
window = GLFW.glfwCreateWindow(500, 500, "thinMatrix4", 0, 0);
if(window == 0){
throw new IllegalStateException("ERROR: during GLFW.glfwCreateWindow");
}
// Context and Capabilities
GLFW.glfwMakeContextCurrent(window); // create context for window
GL.createCapabilities(); // find all the opengl stuff to give capabilities
// Debugging enable
GL11.glEnable(org.lwjgl.opengl.KHRDebug.GL_DEBUG_OUTPUT_SYNCHRONOUS);
debugCallback = GLUtil.setupDebugMessageCallback();
// Position window
GLFWVidMode vidMode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
GLFW.glfwSetWindowPos(window,vidMode.width()/2,vidMode.height()/2);
// Window show
GLFW.glfwShowWindow(window);
}
public static void terminateWindow(){
// Termination
GLFW.glfwTerminate();
}
// GETTERS
public static long getWindow() {
return window;
}
}
Renderer:
public class Renderer {
public void render(Model model){
// Enable to allow model rendering
GL30.glBindVertexArray(model.getVAO());
GL20.glEnableVertexAttribArray(0);
// Render
GL11.glDrawArrays(GL11.GL_TRIANGLES,model.getVertexCount(),0);
// Clean up
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
public void clear(){
GL11.glClearColor(0f,0.8f,.6f,1f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
}
}
Model:
public class Model {
private int vertexCount;
private int vao;
public Model(int vao, int count){
this.vao = vao;
this.vertexCount = count;
}
// GETTERS
public int getVertexCount(){
return this.vertexCount;
}
public int getVAO(){ return this.vao; }
}
public class Loader {
private static List<Integer> vaos = new ArrayList<Integer>();
private static List<Integer> vbos = new ArrayList<Integer>();
public static Model dataToModel(float[] data){
// Create VAO
int vao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vao);
vaos.add(vao);
// Create Buffer (VBO) for actual data
int vbo = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,vbo);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER,toFloatBuffer(data), GL15.GL_STATIC_DRAW); //!##!##!## What happens if data is not a float buffer
// vertex attribute pointer
GL30.glVertexAttribPointer(0,3, GL11.GL_FLOAT,false,0,0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,0);
vbos.add(vbo);
// Create model
int count = data.length/3;
Model model = new Model(vao, count);
return model;
}
private static FloatBuffer toFloatBuffer(float[] data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}
You used glDrawArrays incorrectly. The 2nd argument is the index of the 1st vertex to be rendered and the 3rd argument is the number of vertices:
GL11.glDrawArrays(GL11.GL_TRIANGLES,model.getVertexCount(),0);
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
(This is the second time I am asking this question. Last time I got one answer that didn't solve it (the answer there referred a bit of code that was left accidentally from one of my attempts at fixing this). I also changed the question itself slightly - I changed the order of code to put the part where I believe the mistake higher is and added that I am using macOS, which might be the reason that it doesn't work).
So, I just started learning LWJGL 3 and I used a mixture of a couple of tutorials and example code to make something that should render a rectangle to a magenta screen using VAOs and VBOs. There are no errors but the rectangle doesn't appear on screen (all I can see is a magenta screen). I tried using the old LWJGL pipeline (glBegin() and glEnd()) and it does work so I tried changing random things in the rendering code and the loading to VAOs and VBOs. I also tried to bind the VBO too but it didn't change anything. I also tried debugging and it seems like there is a VAO and a VBO that is created.
Can someone take a look at my code and see if something looks wrong? Here it is (sorry if its a bit messy. Like I said, I don't think the problem is in the Main or Window class but I have no idea about LWJGL so I wanted to put it here anyways. If you have time, please also look at them. Otherwise I would really appreciate it if you could look at the Loader and Renderer classes):
(Btw, I am using macOS, and I do have -XstartOnFirstThread on).
The Raw Model class:
package engine.io;
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;
}
}
The loader class:
package engine.io;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
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);
}
private FloatBuffer storeDataInFloatBuffer(float[] data) {
FloatBuffer buffer = MemoryUtil.memAllocFloat(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
public void cleanUp() {
for (int vao : vaos) {
GL30.glDeleteVertexArrays(vao);
}
for (int vbo : vbos) {
GL15.glDeleteBuffers(vbo);
}
}
}
The renderer class:
package engine.io;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
public class Renderer {
public void prepare() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
GL11.glClearColor(1f, 0f, 1f, 1f);
}
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);
}
}
Here is the Main class:
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
import engine.io.Loader;
import engine.io.RawModel;
import engine.io.Renderer;
import engine.io.Window;
import java.nio.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Main {
private Window window;
Loader loader = new Loader();
Renderer renderer = new Renderer();
float[] vertices = {
// Left bottom triangle
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
// Right top triangle
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f,
-0.5f, 0.5f, 0f
};
RawModel model;
public void run() {
setup();
loop();
loader.cleanUp();
glfwFreeCallbacks(window.getWindowNum());
glfwDestroyWindow(window.getWindowNum());
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private void loop() {
while ( !glfwWindowShouldClose(window.getWindowNum()) ) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
renderer.render(model);
glfwSwapBuffers(window.getWindowNum()); // swap the color buffers
glfwPollEvents();
}
}
public void setup() {
window = new Window(900, 300, "Flappy Bird");
window.create();
GL.createCapabilities();
GLFW.glfwMakeContextCurrent(window.getWindowNum());
model = loader.loadToVAO(vertices);
renderer.prepare();
GL11.glViewport(0, 0, 900, 300);
}
public static void main(String[] args) {
new Main().run();
}
}
Here is the window class:
package engine.io;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.*;
import java.nio.IntBuffer;
//import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.system.MemoryStack;
public class Window {
private int width, height;
private String title;
private long window;
public Window(int width, int height, String title) {
this.width = width;
this.height = height;
this.title = title;
}
public void create() {
GLFWErrorCallback.createPrint(System.err).set();
if (!glfwInit())
throw new IllegalStateException("Unable to initialize GLFW");
// Configure GLFW
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
// Create the window
window = glfwCreateWindow(width, height, "Flappy Bird", NULL, NULL);
if (window == NULL)
throw new RuntimeException("Failed to create the GLFW window");
// Get the thread stack and push a new frame
try (MemoryStack stack = stackPush()) {
IntBuffer pWidth = stack.mallocInt(1); // int*
IntBuffer pHeight = stack.mallocInt(1); // int*
// Get the window size passed to glfwCreateWindow
glfwGetWindowSize(window, pWidth, pHeight);
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center the window
glfwSetWindowPos(window, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
} // the stack frame is popped automatically
// Setup a key callback. It will be called every time a key is pressed, repeated
// or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
});
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public long getWindowNum() {
return window;
}
}
Since you are on MacOS, I recommend to set up a 3.2 core profile OpenGL Context. See OpenGL Development on OS X:
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Create the window
window = glfwCreateWindow(width, height, "Flappy Bird", NULL, NULL);
I've been trying to get into OpenGL with LWJGL and I've run into an issue that I cannot find a solution to. When trying to draw a triangle with the code below, the window opens correctly and begins flashing a shape that isn't necessarily the intended triangle (sometimes it appears briefly, but often there are rectangles in one of the quadrants of the window).
Part of my hesitation is in how OpenGL, by my reading of various posts and docs online, has changed within recent memory to use a less functional and more an object-oriented approach (VBOs and GLSL?) with GL4. Am I correct in this understanding and what are the preferred resources for learning this newer OpenGL for LWJGL?
Thank you in advance!
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
import java.nio.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Main {
private long windowID;
private float[] tri = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f};
public static void main(String[] args) {
new Main().run();
}
public void run() { // Useful for making an instance class as opposed to a static main class?
init();
loop();
glfwFreeCallbacks(windowID);
glfwDestroyWindow(windowID);
glfwTerminate();
glfwSetErrorCallback(null).free();
}
public void init() { // Initializes all LWJGL components
GLFWErrorCallback.createPrint(System.err).set(); // Create error callback route for GL
if (!glfwInit()) { // Init GLFW
throw new IllegalStateException("Failed to initialize GLFW!");
} else {
System.out.println("GLFW successfully initialized!");
}
windowID = glfwCreateWindow(640, 480, "Creating Window", NULL, NULL);
if (windowID == NULL) { // Verify window creation
throw new IllegalStateException("Failed to create window!");
} else {
System.out.println("Successfully created window!");
}
glfwDefaultWindowHints(); // Set window Proporties
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwSetKeyCallback(windowID, (window, key, scancode, action, mods) -> { // Key callback for closing the window
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
glfwSetWindowShouldClose(window, true);
});
try (MemoryStack stack = stackPush()) { // Center the window
IntBuffer pWidth = stack.mallocInt(1);
IntBuffer pHeight = stack.mallocInt(1);
glfwGetWindowSize(windowID, pWidth, pHeight);
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos( // Center the window
windowID,
(vidmode.width() - pWidth.get(0)) / 2,
(vidmode.height() - pHeight.get(0)) / 2
);
}
glfwMakeContextCurrent(windowID); // Make the window current
glfwSwapInterval(0); // Sets the min num of pushed frames before buffers are swaped (Likely prevents horizontal tearing)
glfwShowWindow(windowID); // Unhides the window
}
private void loop() {
GL.createCapabilities();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // The color to clear the buffers with
while(!glfwWindowShouldClose(windowID)) { // If the window is allowed to live
glClear(GL_COLOR_BUFFER_BIT); // The OR is nessesary for some reason
FloatBuffer vBuff = BufferUtils.createFloatBuffer(6);
vBuff.put(tri);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vBuff);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);
glfwSwapBuffers(windowID);
glfwPollEvents();
}
}
}
You missed vBuff.flip() after the buffer was crated and filled.
vBuff.put(tri) transfers the the data to the buffer, beginning at the current position (which is the start of the buffer in this case). The buffer position is incremented by the size of the data. So the new buffer position is at the end of the new data.
flip() sets the limit (length) of the buffer to the current position and then the position is set to zero.
Further, it is not necessary to create and fill the buffer continuously in the loop, it would be sufficient to do that once before the loop:
FloatBuffer vBuff = BufferUtils.createFloatBuffer(6);
vBuff.put(tri);
vBuff.flip();
while(!glfwWindowShouldClose(windowID)) {
glClear(GL_COLOR_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vBuff);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableClientState(GL_VERTEX_ARRAY);
glfwSwapBuffers(windowID);
glfwPollEvents();
}
I'm new to OpenGL and LWJGL3 and I'm trying to render a triangle. However, it isn't showing up, only the white, empty window. I guess it's a pretty small piece that I somehow forgot or where I just made a mistake. I don't find it after searching for hours now though. Here's the code:
MainLoop:
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.glfw.GLFW.*;
public class MainLoop {
private DisplayManager displayManager;
private Shader shader;
public MainLoop() {
displayManager = new DisplayManager();
displayManager.createDisplay();
shader = new Shader("src/shader.vert", "src/shader.frag");
}
private void start() {
float positions[] = {
-0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f
};
int vao = glGenVertexArrays();
glBindVertexArray(vao);
int positionVbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, positionVbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(positions), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
while(!displayManager.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
render();
update();
displayManager.swapBuffers();
}
shader.cleanUp();
displayManager.destroyDisplay();
}
private void update() {
glfwPollEvents();
}
private void render() {
shader.bind();
//rendering stuff
glDrawArrays(GL_TRIANGLES, 0, 3);
shader.unbind();
}
public static void main(String[] args) {
new MainLoop().start();
}
}
Shader:
import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Shader {
private int program;
public Shader(final String vertexShaderFilePath, final String fragmentShaderFilePath) {
int vertexShader = createShader(loadShaderSource(vertexShaderFilePath), GL_VERTEX_SHADER);
int fragmentShader = createShader(loadShaderSource(fragmentShaderFilePath), GL_FRAGMENT_SHADER);
program = glCreateProgram();
glAttachShader(vertexShader, program);
glAttachShader(fragmentShader, program);
glLinkProgram(program);
glValidateProgram(program); //just during development
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
private String loadShaderSource(final String shaderFilePath) {
String shaderSourceString = "";
try {
shaderSourceString = new String(Files.readAllBytes(Paths.get(shaderFilePath)));
} catch (IOException e) {
e.printStackTrace();
}
return shaderSourceString;
}
private int createShader(final String shaderSourceString, final int type) {
int shader = glCreateShader(type);
glShaderSource(shader, shaderSourceString);
glCompileShader(shader);
checkShaderCompileError(shader);
return shader;
}
private void checkShaderCompileError(int shader) {
if(glGetShaderi(shader, GL_COMPILE_STATUS) == GL_FALSE) {
System.err.println("Could not compile shader.");
System.err.println(glGetShaderInfoLog(program));
System.exit(-1);
}
}
public void bind() {
glUseProgram(program);
}
public void unbind() {
glUseProgram(0);
}
public void cleanUp() {
glDeleteProgram(program);
}
}
BufferUtils:
import java.nio.FloatBuffer;
public class BufferUtils {
public static FloatBuffer createFloatBuffer(float[] array) {
FloatBuffer buffer = org.lwjgl.BufferUtils.createFloatBuffer(array.length);
buffer.put(array);
buffer.flip();
return buffer;
}
}
shader.vert:
#version 410 core
layout (location = 0) in vec3 vertex_position;
void main(void)
{
gl_Position = vec4(vertex_position, 1.0);
}
shader.frag:
#version 410 core
out vec4 frag_color;
void main(void)
{
frag_color = vec4(1.0, 0.0, 1.0, 1.0);
}
EDIT: and here's the DisplayManager:
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GLContext.*;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.GLFWvidmode;
public class DisplayManager {
private static final int WIDTH = 1280;
private static final int HEIGHT = 800;
private long window;
private Keyboard keyCallback;
public void createDisplay() {
// initialize GLFW
if(glfwInit() != GL_TRUE) {
System.err.println("GLFW failed to initialize.");
System.exit(-1);
}
// set window hints
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4); //16 for production
// create window
window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", NULL, NULL);
if(window == NULL) {
System.err.println("GLFW window failed to create.");
glfwTerminate();
System.exit(-1);
}
ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - WIDTH) / 2, (GLFWvidmode.height(videoMode) - HEIGHT) / 2);
// set callback mechanisms
glfwSetKeyCallback(window, setKeyCallback(new Keyboard()));
// set context and show window
glfwMakeContextCurrent(window);
createFromCurrent();
glfwSwapInterval(1); // v-sync
glfwShowWindow(window);
// openGL functions
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_DEPTH);
}
public void destroyDisplay() {
glfwDestroyWindow(window);
glfwTerminate();
}
public boolean isCloseRequested() {
if(glfwWindowShouldClose(window) == GL_TRUE) {
return true;
}
return false;
}
public void swapBuffers() {
glfwSwapBuffers(window);
}
public Keyboard getKeyCallback() {
return keyCallback;
}
public Keyboard setKeyCallback(Keyboard keyCallback) {
this.keyCallback = keyCallback;
return keyCallback;
}
}
Does anybody spot what's going wrong?
Thanks in advance!
I finally found the error, the order of parameters for the call glAttachShader(shader, program); were mixed up. You first have to pass the program and then the shader id like so: glAttachShader(program, shader);. Thank you for your answers though!
I am having trouble populating a VAO with my vertex data. I am not sure what the problem is. Here is the error.
Exception in thread "main" java.lang.NullPointerException
at org.lwjgl.opengl.GL30.nglGenVertexArrays(GL30.java:3265)
at org.lwjgl.opengl.GL30.glGenVertexArrays(GL30.java:3294)
at javaapplication73.Loader.createVAO(Loader.java:35)
at javaapplication73.Loader.loadToVao(Loader.java:27)
at javaapplication73.HelloWorld.initial(HelloWorld.java:139)
at javaapplication73.HelloWorld.loop(HelloWorld.java:120)
at javaapplication73.HelloWorld.run(HelloWorld.java:32)
at javaapplication73.HelloWorld.main(HelloWorld.java:154)
Java Result: 1
And here is the loader class which is throwing the exception
public class Loader {
private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();
public RawModel loadToVao(float[] positions){
int vaoID = this.createVAO();
this.storeDataInAttributeList(0, positions);
this.unbindVAO();
return new RawModel(1, positions.length/3);
}
private int createVAO(){
int vaoID = GL30.glGenVertexArrays(1, vao);
vaos.add(vaoID);
GL30.glBindVertexArray(vaoID);
return vaoID;
}
public 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);
}
public void unbindVAO(){
//unbind the array
GL30.glBindVertexArray(0);
}
private FloatBuffer storeDataInFloatBuffer(float[] data){
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
//need to flip between wright and read
buffer.flip();
return buffer;
}
public void cleanUp(){
for (Integer vao : this.vaos) {
GL30.glDeleteVertexArrays(vao);
}
for(Integer vbo : this.vbos){
GL15.glDeleteBuffers(vbo);
}
}
}
Here is the Main class
package javaapplication73;
public class HelloWorld {
// We need to strongly reference callback instances.
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;
// The window handle
private long window;
private final int fpsCap = 120;
Loader loader = new Loader();
Renderer renderer = new Renderer();
private RawModel model;
public void run() {
System.out.println("Hello LWJGL " + Sys.getVersion() + "!");
try {
init();
loop();
// Release window and window callbacks
glfwDestroyWindow(window);
keyCallback.release();
} finally {
// Terminate GLFW and release the GLFWerrorfun
glfwTerminate();
errorCallback.release();
}
}
private void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( glfwInit() != GL11.GL_TRUE )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure our window
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
int WIDTH = 1200;
int HEIGHT = 800;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Not so Still Life", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, GL_TRUE); // We will detect this in our rendering loop
cleanUp();
}
});
// Get the resolution of the primary monitor
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(GLFWvidmode.width(vidmode) - WIDTH) / 2,
(GLFWvidmode.height(vidmode) - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
private void loop() {
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the ContextCapabilities instance and makes the OpenGL
// bindings available for use.
GLContext.createFromCurrent();
// Set the clear color
glClearColor(.3243f,0,.83251234f,0);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
while ( glfwWindowShouldClose(window) == GL_FALSE ) {
// Clear the screen and depth buffer
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
initial();
Render();
glfwSwapBuffers(window); // swap the color buffers
glfwPollEvents();
}
}
public void initial(){
System.out.println(glGetString(GL_VERSION));
//Pre game stuff
float[] verticies = {
-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,
};
model = loader.loadToVao(verticies);
}
public void Render(){
renderer.prepare();
renderer.Render(model);
}
public void cleanUp(){
System.out.println("CleanUp");
this.loader.cleanUp();
}
public static void main(String[] args) {
System.setProperty("org.lwjgl.librarypath", "/Users/Bayjose/LWJGL/lwjgl/native");
new HelloWorld().run();
}
}
I am running Mac OSX Yosemite with Java 8, and I am useing LWJGL3 as a library for this project.
Remove arguments 1 and vao so
int vaoID = GL30.glGenVertexArrays();