text: # static methods to load and compile OpenGL shader programs
  from OpenGL.GL import *
  
  import pygame  # for loading images / texture data
  
  
  class OpenGLUtils(object):
  
      @staticmethod
      def initializeShader(shaderCode, shaderType):
          extension = '#extension GL_ARB_shading_language_420pack : require\n'
          shaderCode = '#version 130\n' + extension + shaderCode
  
          # create empty shader object and return reference value
          shaderID = glCreateShader(shaderType)
          # stores the source code in the shader
          glShaderSource(shaderID, shaderCode)
          # compiles source code previously stored in the shader object
          glCompileShader(shaderID)
  
          # queries whether shader compile was successful
          compileSuccess = glGetShaderiv(shaderID, GL_COMPILE_STATUS)
          if not compileSuccess:
              # retreive error message
              errorMessage = glGetShaderInfoLog(shaderID)
              # free memory used to store shader program
              glDeleteShader(shaderID)
              # TODO: parse str(errorMessage) for better printing
              raise Exception(errorMessage)
  
          # compilation was successful; return shader reference value
          return shaderID
  
      @staticmethod
      def initializeShaderFromCode(vertexShaderCode, fragmentShaderCode):
  
          vertexShaderID = OpenGLUtils.initializeShader(vertexShaderCode,
                                                        GL_VERTEX_SHADER)
          fragmentShaderID = OpenGLUtils.initializeShader(fragmentShaderCode,
                                                          GL_FRAGMENT_SHADER)
  
          programID = glCreateProgram()
          glAttachShader(programID, vertexShaderID)
          glAttachShader(programID, fragmentShaderID)
          glLinkProgram(programID)
  
          return programID
  
      """
      @staticmethod
      def initializeShaderFromFiles(vertexShaderFileName, fragmentShaderFileName):
  
          vertexShaderFile = open(vertexShaderFileName, mode='r')
          vertexShaderCode = vertexShaderFile.read()
          vertexShaderFile.close()
  
          fragmentShaderFile = open(fragmentShaderFileName, mode='r')
          fragmentShaderCode = fragmentShaderFile.read()
          fragmentShaderFile.close()
  
          return OpenGLUtils.initializeShaderFromCode(vertexShaderCode, fragmentShaderCode)
      """
  
      @staticmethod
      def initializeTexture(imageFileName):
          # load image from file
          surface = pygame.image.load(imageFileName)
          return OpenGLUtils.initializeSurface(surface)
  
      @staticmethod
      def initializeSurface(surface):
          # transfer image to string buffer
          textureData = pygame.image.tostring(surface, "RGBA", 1)
          width = surface.get_width()
          height = surface.get_height()
          # glEnable(GL_TEXTURE_2D)
          texid = glGenTextures(1)
          glBindTexture(GL_TEXTURE_2D, texid)
  
          # send image data to texture buffer
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
                       GL_UNSIGNED_BYTE, textureData)
  
          # generate a mipmap for use with 2d textures
          glGenerateMipmap(GL_TEXTURE_2D)
  
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
          #use the mip map filter rather than standard filter
          glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                          GL_LINEAR_MIPMAP_LINEAR)
          # useless - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE)
          return texid
  