title: How to draw with Vertex Array Objects and glDrawElements in PyOpenGL
body: <p>I have the following code which should simply draw a green triangle to the screen. It is using Vertex Array Objects and index buffers to draw and has the simplest shader I could make.</p>
  
  <p>At first I was not using index buffers and was simply making the draw call with <code>glDrawArrays</code> which worked fine but when I change it to use <code>glDrawElements</code> then nothing is drawn to the screen (it is entirely black).</p>
  
  <pre><code>from OpenGL.GL import shaders
  from OpenGL.arrays import vbo
  from OpenGL.GL import *
  from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, \
                                                    glBindVertexArray
  
  import pygame
  
  import numpy as np
  
  def run():
      pygame.init()
      screen = pygame.display.set_mode((800,600), pygame.OPENGL)
  
      #Create the Vertex Array Object
      vertexArrayObject = GLuint(0)
      glGenVertexArrays(1, vertexArrayObject)
      glBindVertexArray(vertexArrayObject)
  
      #Create the VBO
      vertices = np.array([[0,1,0],[-1,-1,0],[1,-1,0]], dtype='f')
      vertexPositions = vbo.VBO(vertices)
  
      #Create the index buffer object
      indices = np.array([0,1,2], dtype='uint16')
      indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)
  
      indexPositions.bind()
      vertexPositions.bind()
  
      glEnableVertexAttribArray(0) # from 'location = 0' in shader
      glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, None)
  
      glBindVertexArray(0)
      vertexPositions.unbind()
      indexPositions.unbind()
  
      #Now create the shaders
      VERTEX_SHADER = shaders.compileShader("""
      #version 330
      layout(location = 0) in vec4 position;
      void main()
      {
          gl_Position = position;
      }
      """, GL_VERTEX_SHADER)
  
      FRAGMENT_SHADER = shaders.compileShader("""
      #version 330
      out vec4 outputColor;
      void main()
      {
          outputColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);
      }
      """, GL_FRAGMENT_SHADER)
  
      shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
  
      #The draw loop
      while True:
          glUseProgram(shader)
          glBindVertexArray(vertexArrayObject)
  
          #glDrawArrays(GL_TRIANGLES, 0, 3) #This line works
          glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0) #This line does not
  
          glBindVertexArray(0)
          glUseProgram(0)
  
          # Show the screen
          pygame.display.flip()
  
  run()
  </code></pre>
  
  <p>If I simply comment out the <code>glDrawElements</code> and uncomment the <code>glDrawArrays</code> line then it works correctly so at least the vertex VBO is being input correctly.</p>
  
  <p>What am I doing wrong here? All the OpenGL documentation I have been able to find suggests that I am doing this correctly so I am obviously misunderstanding something either about OpenGL itself or the PyOpenGL wrapper.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Changing the VAO setup to use more direct OpenGL function rather than the VBO wrapper like:</p>
  
  <pre><code>vertices = np.array([[0,1,0],[-1,-1,0],[1,-1,0]], dtype='f')
  vertexPositions = glGenBuffers(1)
  glBindBuffer(GL_ARRAY_BUFFER, vertexPositions)
  glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW)
  
  #Create the index buffer object
  indices = np.array([0,1,2], dtype='uint16')
  indexPositions = glGenBuffers(1)
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexPositions)
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
  
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexPositions)
  glBindBuffer(GL_ARRAY_BUFFER, vertexPositions)
  
  glEnableVertexAttribArray(0) # from 'location = 0' in shader
  glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, None)
  
  glBindVertexArray(0)
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
  glBindBuffer(GL_ARRAY_BUFFER, 0)
  </code></pre>
  
  <p>makes no difference. <code>glDrawArrays</code> still works and <code>glDrawElements</code> still doesn't.</p>