PyOpenGL: Rendering... Well... Anything really
Question: I've been working on a project using python with OpenGL for a while now. I
previously posted a similar problem, but I have since done some more research
and switched to non-deprecated functions. Following [this
tutorial](http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-
Contents.html) (Translating it to Python versions obviously) I end up with
this code:

    
    
    import sys
    import OpenGL
    
    from OpenGL.GL import *
    from OpenGL.GL.shaders import *
    from OpenGL.GLU import *
    from OpenGL.GLUT import *
    from OpenGL.GLUT.freeglut import *
    from OpenGL.arrays import vbo
    import pygame
    import Image
    import numpy    
    
    class AClass:
        def __init__(self):
            self.Splash = True    #There's actually more here, but it's impertinent
        def TexFromPNG(self, filename):
            img = Image.open(filename) # .jpg, .bmp, etc. also work
            img_data = numpy.array(list(img.getdata()), 'B')
            texture = glGenTextures(1)
            glPixelStorei(GL_UNPACK_ALIGNMENT,1)
            glBindTexture(GL_TEXTURE_2D, texture)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.size[0], img.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
            return texture
        def MakeBuffer(self, target, data, size):
            TempBuffer = glGenBuffers(1)
            glBindBuffer(target, TempBuffer)
            glBufferData(target, size, data, GL_STATIC_DRAW)
            return TempBuffer
        def ReadFile(self, filename):
            tempfile = open(filename,'r')
            source = tempfile.read()
            temprfile.close()
            return source
        def run(self):
            glutInitDisplayMode(GLUT_RGBA)
    
            glutInitWindowSize(256,244)
            self.window = glutCreateWindow("test")
            glutReshapeFunc(self.reshape)
            glutDisplayFunc(self.draw)
            glutKeyboardFunc(self.keypress)
    
            self.MainTex = glGenTextures(1)
            self.SplashTex = self.TexFromPNG("Resources/Splash.png")
            MainVertexData = numpy.array([-1,-1,1,-1,-1,1,1,1],numpy.float32)
            FullWindowVertices = numpy.array([0,1,2,3],numpy.ushort)
            self.MainVertexData = self.MakeBuffer(GL_ARRAY_BUFFER,MainVertexData,len(MainVertexData))
            self.FullWindowVertices = self.MakeBuffer(GL_ELEMENT_ARRAY_BUFFER,FullWindowVertices,len(FullWindowVertices))
            self.BaseProgram = compileProgram(compileShader(self.ReadFile("Shaders/Mainv.glsl"),
                                             GL_VERTEX_SHADER),
                                             compileShader(self.ReadFile("Shaders/Mainf.glsl"),
                                             GL_FRAGMENT_SHADER))
            glutMainLoop()
        def reshape(self, width, height):
            self.width = width
            self.height = height
            glutPostRedisplay()
        def draw(self):
            glViewport(0, 0, self.width, self.height)        
    
            glClearDepth(1)
            glClearColor(0,0,0,0)
            glClear(GL_COLOR_BUFFER_BIT)
            glEnable(GL_TEXTURE_2D)
            if self.Splash:
                glUseProgram(self.BaseProgram)
                pos = glGetAttribLocation(self.BaseProgram, "position")
                glActiveTexture(GL_TEXTURE0)
                glBindTexture(GL_TEXTURE_2D, self.SplashTex)
                glUniform1i(glGetUniformLocation(self.BaseProgram,"texture"), 0)
    
                glBindBuffer(GL_ARRAY_BUFFER,self.MainVertexData)
                glVertexAttribPointer(pos,
                                      2,
                                      GL_FLOAT,
                                      GL_FALSE,
                                      0,
                                      numpy.array([0],numpy.uint8))
                glEnableVertexAttribArray(pos)
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,self.FullWindowVertices)
                glDrawElements(GL_TRIANGLE_STRIP,
                               4,
                               GL_UNSIGNED_SHORT,
                               numpy.array([0],numpy.uint8))
                glDisableVertexAttribArray(pos)
            else:
                glBindTexture(GL_TEXTURE_2D, self.MainTex)
    
    
    
            glutSwapBuffers()
    glutInit(sys.argv)
    test = AClass()
    test.run()
    

Shaders/Mainv.glsl and Shaders/Mainf.glsl contain:

    
    
    #version 110
    
    attribute vec2 position;
    
    varying vec2 texcoord;
    
    void main()
    {
        gl_Position = vec4(position, 0.0, 1.0);
        texcoord = position * vec2(0.5) + vec2(0.5);
    }
    

and:

    
    
    #version 110
    
    uniform sampler2D texture;
    
    varying vec2 texcoord;
    
    void main()
    {
        gl_FragColor = texture2D(texture, texcoord);
     }
    

respectively.

This code nets me with a (clear color) GLUT window, which seems to suggest
that it's not rendering my triangles for some reason, but I have no idea why
that could be, and I can't really find any examples for PyOpenGL that don't
use deprecated functions, so I can't see if they did anything different from
me that I'm missing.


Answer: I think this is a useful reference for anyone starting out with PyOpenGL and
the programmable pipleline, so I've corrected the code according to comments
by Bethor and Josiah above, and have also simplified it a bit (embedded the
shaders as strings). This code works for me. It assumes that you have
**test.png** in the same directory.

    
    
    import sys
    import OpenGL
    
    from OpenGL.GL import *
    from OpenGL.GL.shaders import *
    from OpenGL.GLU import *
    from OpenGL.GLUT import *
    from OpenGL.GLUT.freeglut import *
    from OpenGL.arrays import vbo
    import Image
    import numpy    
    
    # vertex shader
    strVS = """
    attribute vec2 position;
    
    varying vec2 texcoord;
    
    void main()
    {
        gl_Position = vec4(position, 0.0, 1.0);
        texcoord = position * vec2(0.5) + vec2(0.5);
    }
    """
    
    # fragment shader
    strFS = """
    uniform sampler2D texture;
    
    varying vec2 texcoord;
    
    void main()
    {
        gl_FragColor = texture2D(texture, texcoord);
    }
    """
    
    class AClass:
        def __init__(self):
            self.Splash = True    #There's actually more here, but it's impertinent
        def TexFromPNG(self, filename):
            img = Image.open(filename) # .jpg, .bmp, etc. also work
            img_data = numpy.array(list(img.getdata()), 'B')
            texture = glGenTextures(1)
            glPixelStorei(GL_UNPACK_ALIGNMENT,1)
            glBindTexture(GL_TEXTURE_2D, texture)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.size[0], img.size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
            return texture
        def MakeBuffer(self, target, data, size):
            TempBuffer = glGenBuffers(1)
            glBindBuffer(target, TempBuffer)
            glBufferData(target, size, data, GL_STATIC_DRAW)
            return TempBuffer
        def run(self):
            glutInitDisplayMode(GLUT_RGBA)
    
            glutInitWindowSize(256,244)
            self.window = glutCreateWindow("test")
            glutReshapeFunc(self.reshape)
            glutDisplayFunc(self.draw)
    
            self.MainTex = glGenTextures(1)
            self.SplashTex = self.TexFromPNG("test.png")
            MainVertexData = numpy.array([-1,-1,1,-1,-1,1,1,1],numpy.float32)
            FullWindowVertices = numpy.array([0,1,2,3],numpy.ushort)
            self.MainVertexData = self.MakeBuffer(GL_ARRAY_BUFFER,MainVertexData,4*len(MainVertexData))
            self.FullWindowVertices = self.MakeBuffer(GL_ELEMENT_ARRAY_BUFFER,FullWindowVertices,2*len(FullWindowVertices))
            self.BaseProgram = compileProgram(compileShader(strVS,
                                                            GL_VERTEX_SHADER),
                                              compileShader(strFS,
                                                            GL_FRAGMENT_SHADER))
            glutMainLoop()
        def reshape(self, width, height):
            self.width = width
            self.height = height
            glutPostRedisplay()
        def draw(self):
            glViewport(0, 0, self.width, self.height)        
    
            glClearDepth(1)
            glClearColor(0,0,0,0)
            glClear(GL_COLOR_BUFFER_BIT)
            glEnable(GL_TEXTURE_2D)
            if self.Splash:
                glUseProgram(self.BaseProgram)
                pos = glGetAttribLocation(self.BaseProgram, "position")
                glActiveTexture(GL_TEXTURE0)
                glBindTexture(GL_TEXTURE_2D, self.SplashTex)
                glUniform1i(glGetUniformLocation(self.BaseProgram,"texture"), 0)
    
                glBindBuffer(GL_ARRAY_BUFFER,self.MainVertexData)
                glVertexAttribPointer(pos,
                                      2,
                                      GL_FLOAT,
                                      GL_FALSE,
                                      0,
                                      None)
                glEnableVertexAttribArray(pos)
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,self.FullWindowVertices)
                glDrawElements(GL_TRIANGLE_STRIP,
                               4,
                               GL_UNSIGNED_SHORT,
                               None)
                glDisableVertexAttribArray(pos)
            else:
                glBindTexture(GL_TEXTURE_2D, self.MainTex)
    
            glutSwapBuffers()
    
    glutInit(sys.argv)
    test = AClass()
    test.run()
    
    

Here is the output:

![enter image description here](http://i.stack.imgur.com/wLv0g.png)

