Unable to get glDrawElements to work.

Started by Teracon, June 10, 2015, 16:54:48

Previous topic - Next topic

Teracon

My shader works fine, and I can draw with glDrawArrays, but am having a hard time getting glDrawElements to work. The clearcolor is showing up across the whole window, but nothing else is working. I'm using scala, which supports java libraries natively. I've tried looking for similar errors to no avail. Code:

    import org.lwjgl.Sys
    import org.lwjgl.glfw._
    import org.lwjgl.opengl._
    import java.nio.ByteBuffer
    import java.nio.FloatBuffer
    import  org.lwjgl.glfw.Callbacks._
    import  org.lwjgl.glfw.GLFW._
    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._
    import  org.lwjgl.BufferUtils._
    import hands._
    import javafx.scene.shape.CullFace
    
    
    class Test {
       
        val vertex_positions:  Array[Float] = Array(
         -1.0f, -1.0f, 0.0f,  
         1.0f, -1.0f, 0.0f,
         -1.0f, 1.0f, 0.0f
        )
        
        val vertex_indices: Array[Int] = Array(
          0, 1, 2    
        )
    
        // We need to strongly reference callback instances.
        val errorCallback: GLFWErrorCallback = Callbacks.errorCallbackPrint();
        val keyCallback: GLFWKeyCallback = new GLFWKeyCallback() {
          @Override
          def invoke(window: Long , key: Int, scancode: Int , action: Int , mods: Int) {
            if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
              glfwSetWindowShouldClose(window, GL_TRUE) // We will detect this in our rendering loop
          }
        }
        
        val WIDTH = 800
        val HEIGHT = 600 
    
        def run(): Unit = {
        		System.out.println("Hello LWJGL " + Sys.getVersion() + "!")  
    
        		try {
    
        			val vertBuffer = hands.createFlippedBuffer(vertex_positions)
        			val indexBuffer = hands.createFlippedBuffer(vertex_indices)
    
        			// Setup an error callback. The default implementation
        			// will print the error message in System.err.
        			glfwSetErrorCallback(errorCallback)
    
        			// Initialize GLFW. Most GLFW functions will not work before doing this.
        			if ( glfwInit() != 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
        			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
        			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
        			glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
    
        			// Create the window
        			val window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", 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)
    
        			// Get the resolution of the primary monitor
        			val vidmode: ByteBuffer = 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)
      
      				// 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()
      				
                                //create shader, and use it as program
                                val shader = new Shader()
        			glUseProgram(shader.program)
              
        			val vao = glGenVertexArrays()
        			glBindVertexArray(vao)
        			
        			val vbo = glGenBuffers()
        			glBindBuffer(GL_ARRAY_BUFFER, vbo)
                                //http://javadoc.lwjgl.org/org/lwjgl/opengl/GL15.html#glBufferData%28int,%20java.nio.FloatBuffer,%20int%29
        			glBufferData(GL_ARRAY_BUFFER,  vertBuffer, GL_STATIC_DRAW)
              
                                 //this function accepts false instead of GL_FALSE
        			glVertexAttribPointer(0, 3, GL_FLOAT, false , 0, 0)
                                glEnableVertexAttribArray(0)
              
        			val ebo = glGenBuffers()
        			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
                                 //http://javadoc.lwjgl.org/org/lwjgl/opengl/GL15.html#glBufferData%28int,%20java.nio.ShortBuffer,%20int%29
        			glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW)
    
    
        			// Set the clear color
        			glClearColor(0, 0, 0.4f, 1)
        			// Run the rendering loop until the user has attempted to close
        			// the window or has pressed the ESCAPE key.
                               //glfwWindowShouldClose produces a GL_FALSE, instead of a boolean value
        			while ( glfwWindowShouldClose(window) == GL_FALSE ) {
    
        			glClear(GL_COLOR_BUFFER_BIT) // clear the framebuffer
    
        			glBindVertexArray(vao)
        			glEnableVertexAttribArray(0)
    
        		        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
                
                    
        		     GL11.glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0)
        		     //glDrawArrays(GL_TRIANGLES, 0, 9)
        				
                            glfwSwapBuffers(window); // swap the color buffers
        				
                              // Poll for window events. The key callback above will only be
        		      // invoked during this call.
        		     glfwPollEvents();
        	    }
     
                // Release window and window callbacks            
                glfwDestroyWindow(window)
                keyCallback.release()
            } finally {
                // Terminate GLFW and release the GLFWerrorfun
                glfwTerminate()
                errorCallback.release()
            }
        }
        
    }
    
    object main{
          
          def main( args: Array[String] ) = {
              new Test().run();
          }
        }

Sorry about the weird formatting towards the bottom, something is going on with my tabs.
Thank you for your help.

Kai

Hm... cannot see any obvious error.
The only thing I can think of is hands.createFlippedBuffer() not working as expected when being called with an int array.
Make sure that this method overload really creates a direct ByteBuffer (or an IntBuffer view) with native byte order and that it is filled with integers (i.e. via a IntBuffer view or via the putInt() methods on the ByteBuffer) and that this buffer is really flipped. Preferably use LWJGL's BufferUtils utility class to do that.
I do not expect it, but if you are unsure about possible GL errors occurring, you can enable debug outputs like how it's done in the Gears Demo.
Other than that you have a few redundant GL calls, such as the glEnableVertexAttribArray in line 130 and the glBindBuffer below that in line 132.
Note that vertex attribute enable status and the buffer bindings are part of the VAO state, which you initially set in line 112 and 115, respectively.
Oh and that glDrawArrays, which is currently commented, should use 3 instead of the 9.

Teracon

This is the Int overload for hands:
    def createFlippedBuffer(bufferArray: Array[Int]) = {
    
    val byteBuffer = createIntBuffer(bufferArray.length)
    byteBuffer.put(bufferArray)
    byteBuffer.flip()
    byteBuffer
    
  }


Which leads me to believe I'm not actually loading the Ints correctly, but it appears to be using the same logic used in other programs I've seen for defining indices. I'll set up the debug info and see if that generates something.

Edit: I believe I set up the debug correctly, (context.setupDebugMessageCallback(System.err)), but it's not putting out any errors.

Kai

Added a simple demo showcasing the use of glDrawElements. This effectively really does not do anything else than what you did, but works perfectly for me, though.
Could you send/attach the .class files generated by the Scala compiler for your demo and for that hand method? There we can check what Scala really is doing.

Teracon

I copy/pasted your code and scalafied it, and it works. Scala for some reason didn't like (FloatBuffer) BufferUtils.createFloatBuffer(vertices.length).put(vertices).flip() and the similar line; I broke them out as three lines and it accepted; I'm thinking it was a type error (along the functions pushing things up). Looks like I need to diff some things, because I don't even know. Mass type checking I guess. Thank you! Would you be interested in seeing the scalafied copy/paste I did?

Edit:
More strangeness: removing wsCallback and referenced items from my copy/pasted code causes the error, but adding it to my code does not fix it.

Kai

I would be quite interested in the original (non-working) .class files, to see what exactly Scala was doing there. Thanks!

Teracon

Here they are, I didn't see you ask for them the first time around.

Kai

Could you please also attach the test class, of which you showed the Scala code above?

Kai

Quote from: Teracon on June 10, 2015, 18:39:04
More strangeness: removing wsCallback and referenced items from my copy/pasted code causes the error, but adding it to my code does not fix it.
Ah, then it was probably the glViewport which you was missing in your code. This method is needed when you resize the window to tell OpenGL about the changed viewport size.
Because, you did realize that this window size callback was setting the instance fields "width" and "heigh" which were being used by glViewport?

Teracon

Attached the files. At some point in time I did add a viewport, and was using the WIDTH and HEIGHT constants. I did not have width/height aside from those constants. I got my version to work, and think maybe it was a strange ordering of setting up the buffers?

Edit: Upon further finagalling, this appears to not be the case. Thank you so much for your help, whatever it was that did it. Maybe the last zero in glVertexAttribPointer wasn't properly casting as a long?

Kai

Now slow down... :)
That test classes which you attached in your last post ARE NOT the compile of your original test class from your very first post, which I asked about. They are the result of my demo class being translated to Scala by you. If we are ever going to find the error, I conjure you to use your non-working Scala code of your very first post again, and attach THOSE class files. :)
I mean there is no use in trying to dissect a "working" code...

Teracon

Aw crap, sorry. I've been working on this for two days and been utterly confused past the first two hours.

Interesting note: I copied the original code from this post, and it works now. I don't even.


Teracon

On the one hand, I'm glad it's working now. On the other, I'm reasonably sure that this is going to generate an even more mind boggling error close to release >_> Thank you so much for your help! Whatever form that came in.