::[ USING OPENGL VIA PYGAME ]::[ Source ]::[ Printable Version ]::
 
::[ AUTHOR - Codeboy, codeboy@postmark.net ]::
(OpenGL Comments: Willie Tang)

 
::[ CAST OF CHARACTERS ]::
OpenGL - A very widely adopted industry standard 3D graphics API with extensive support on different platforms. Hardware accelerated drivers for OpenGL are readily available for virtually all modern cards on Windows, Mac OS X, and Linux/BSD/*nix. See: http://www.opengl.org

Python - A very widely adopted industry standard 3D graphics API with extensive support on different platforms. Hardware accelerated drivers for OpenGL are readily available for virtually all modern cards on Windows, Mac. See: http://www.python.org

SDL (Simple DirectMedia Layer) - SDL provides a simple, unified graphics/sound/input/CD API which works on the most popular platforms including Windows, Mac OS X, Linux, *BSD. It is built on top of the native APIs of these platforms thereby taking advantage of any hardware acceleration for graphics and sound that these APIs provide. For example, under Windows, SDL can use DirectX to accelerate its blit functionality. In lieu of its own 2D API, SDL also provides an OpenGL context which you can use in conjunction with the other non-graphics SDL APIs. See: http://www.libsdl.org

PyGame - A Python binding/wrapper for SDL that makes SDL's already easy-to-understand API even simpler to use and exposes it to all the power of Python. See: http://www.pygame.org

PyOpenGL - A Python binding for OpenGL that allows Python programs to use the OpenGL API. PyOpenGL works with many GUI libraries including wxPython, FxPy, Tkinter, etc....and of course, PyGame. See: http://pyopengl.sf.net  

 
::[ BENEFITS OF USING OPENGL UNDER PYGAME ]::

  • Python's high level nature makes for very rapid development
  • Hardware accelerated OpenGL is widespread and readily exposed by PyOpenGL
  • Python's, SDL/Pygame's, and PyOpenGL's cross platform nature means that it is very possible to write a single piece of source code that will work on multiple platforms unchanged (as we shall see in the example)
 
::[ REQUIREMENTS ]::
You should have Python, Pygame (incl. the auxiliary libraries for sound mentioned in the pygame page), PyOpenGL, and the SDL libraries installed on your computer. You should also make sure that OpenGL is properly installed and running on your platform. Configuring these may take a bit of trial and error (esp. on Linux) and is beyond the scope of this article...but hopefully it is not that hard.  

 
::[ THE SAMPLE CODE ]::
The following Python code has been tested under both Windows and Linux and work identically. In theory, the same should apply on any other platform where Pygame/PyOpenGL is available. One can see that it is absolutely free of any platform specific code including #ifdefs as well as of any code having to do with platform detection. In spite of this it will transparently take advantage of any 3d acceleration capability available (assuming you installed your OpenGL drivers properly) on your system!

Python is very easy to understand so I will just let the source code and comments guide your understanding.  

 
::[ CONTROLLING THE PROGRAM ]::
The program displays 2 rotatable squares superimposed on each other. A smaller inner square (a GL_QUAD), with vertex assigned color and a larger outer square with an alpha-transparency enabled texture.

The 1, 2, and 3 keys control the rotation of the smaller inner square while the 4, 5, and 6 keys that of the outer square. Pressing the keys plays a random wave file - this is to demonstrate how we use Pygame for sound playback.  

 
::[ ABOUT THE CODE ]::
The code uses vertex arrays for speed. Note that PyOpenGL 2.0.0.44 will not handle vertex arrays properly unless you apply a patch to it. As far as I know, the PyOpenGL people have not applied this simple patch to the stable 2.0.0.44 release so you probably have to do this yourself. Search for 'glTexCoordPointer' in the PyOpenGL mailing list for a discussion of how to do the patch.  

 
::[ START OF LISTING ]::

import sys                        # All we will use is the sys.exit() routine
import pygame                     # Tell python we want to use the pygame module
from random        import choice  # Imports the choice() function 
                                  #   from the random module
from pygame.locals import *       # Imports the constant symbols from 
                                  #   pygame.locals - like OPENGL, K_1, etc...
from OpenGL.GL     import *       # This is so we can just do glXXXX() 
                                  #   instead of OpenGL.GL.glXXXXX()

rot1=0
rot2=0
direction1=0
direction2=0

# Colors for the inner rectangle
square1Colors=[[1,0,0,1],[0,1,0,1],[0,0,1,1],[1,1,1,1]]

# Vertices of the inner rectangle
square1Vertices=[[-64,-64],[64,-64],[64,64],[-64,64]]          

# Texture coordinates for the outer rectangle
square2TexCoords=[[0,0],[1,0],[1,1],[0,1]]   
                  
# Vertices of the outer rectangle
square2Vertices=[[-128,-128],[128,-128],[128,128],[-128,128]]  

def draw ():
  # global means use the values declared in the global scope outside this function
  global rot1,rot2,direction1,direction2
  global square1Colors,square1Vertices,square2TexCoords,square2Vertices
  glClearColor(0.0,0.0,0.0,0.0)
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

  # Select GL_MODELVIEW matrix
  glMatrixMode(GL_MODELVIEW)  
  
  # Save current GL_MODELVIEW matrix state
  glPushMatrix()              
  
  # Translate 200 units to the right and back
  glTranslatef(200,200,0)     

  # Tell OpenGL that we will use a color-array
  glEnableClientState(GL_COLOR_ARRAY)       

  # Tell OpenGL that we will use a vertex-array
  glEnableClientState(GL_VERTEX_ARRAY)      

  # square1Colors contains colors for square1
  glColorPointerf(square1Colors)            

  # square1Vertices contains vertices for square1
  glVertexPointerf(square1Vertices)         

  glRotatef(rot2,0,0,1)                     # Rotate square1 around (0,0,1)
  rot2=(rot2+direction2)%360                # Update rot2 value
  glBegin(GL_QUADS)                         # Tell OpenGL that we will draw quads
  glArrayElement(0)                         # First element in vertex-array
  glArrayElement(1)                         # Second element in vertex-array
  glArrayElement(2)                         # Third element in vertex-array
  glArrayElement(3)                         # Fourth element in vertex-array
  glEnd()
  glDisableClientState(GL_COLOR_ARRAY)      # Disable color-array

  # Restore last GL_MODELVIEW matrix state
  glPopMatrix()                             

  # Save current GL_MODELVIEW matrix state
  glPushMatrix()                            

  # Translate 200 units to the right and back
  glTranslatef(200,200,0)                   
 
  # Enable 2D texturemapping
  glEnable(GL_TEXTURE_2D)                   

  # Enable blending
  glEnable(GL_BLEND)                        
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)   # Define blending function

  # Tell OpenGL that we will use a texture-coord-array
  glEnableClientState(GL_TEXTURE_COORD_ARRAY)        

  # Tell OpenGL that we will use a vertex-array
  glEnableClientState(GL_VERTEX_ARRAY)     

  # square2TexCoords contains texture coordinates for square2          
  glTexCoordPointerf(square2TexCoords)     

  # square2Vertices contains vertices for square2
  glVertexPointerf(square2Vertices)        

  glRotatef(rot1,0,0,1)                    # Rotate squre2 around (0,0,1)
  rot1=(rot1+direction1)%360               # Update rot1 value
  glBegin(GL_QUADS)                        # Tell OpenGL that we will draw quads
  glArrayElement(0)                        # First element of vertex-array
  glArrayElement(1)                        # Second element of vertex-array
  glArrayElement(2)                        # Third element of vertex-array
  glArrayElement(3)                        # Fourth element of vertex-array
  glTexCoord2f(0,0)
  glEnd()
  glDisable(GL_BLEND)                      # Disable blending state
  glDisable(GL_TEXTURE_2D)                 # Disable 2D texturemapping
  
  glFlush()                                # Flush everything to screen ASAP

  # Restore last GL_MODELVIEW matrix state
  glPopMatrix()                            
  pygame.display.flip()                    # Flip the double-buffer

pygame.init()  # kickstart pygame

# we want a fullscreen, 1280x1024, SDL surface that supports doublebuffered OpenGL
pygame.display.set_mode((1280,1024),OPENGL|DOUBLEBUF|FULLSCREEN)

# create the partially transparent texture
# pixel format is: \xRR\xGG\xBB\xAA Red,Green,Blue,Alpha
tex=""
for i in xrange(512):
  tex+="\xff\xff\xff\x7f\xff\xff\xff\x7f\xff\xff\xff\x7f\xff\xff\xff\x7f"
  tex+="\xff\xff\xff\x3f\xff\xff\xff\x3f\xff\xff\xff\x3f\xff\xff\xff\x3f"

glTexImage2D(GL_TEXTURE_2D,0,4,64,64,0,GL_RGBA,GL_UNSIGNED_BYTE,tex)

# Clamp our texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP)        
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP)        

# Magnification filter is linear
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)   

# Minification filter is linear
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)   

# Texture will not be affected by current color state
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)       
glDisable(GL_DEPTH_TEST)                # No depth testing

glMatrixMode(GL_PROJECTION)             # Select GL_PROJECTION matrix
glLoadIdentity()                        # Reset GL_PROJECTION matrix
glOrtho (0,1280,0,1024,-1,1)            # Set up orthographic projection

draw()                                  # Call draw function


# put random wave files in the soundList list
# provide your own .wav files
soundList=[]
soundList.append(pygame.mixer.Sound("dingdong.wav"))
soundList.append(pygame.mixer.Sound("trumpet1.wav"))
soundList.append(pygame.mixer.Sound("boo.wav"))

# the nice and simple event loop
while 1:
  event=pygame.event.poll ()

  if event.type is QUIT:
    sys.exit(0)

  draw()

  if event.type is KEYDOWN:
    if event.key is K_ESCAPE:
      sys.exit(0)
    if event.key is K_1:
      choice(soundList).play()
      direction2=2
    if event.key is K_2:
      choice(soundList).play()
      direction2=-2
    if event.key is K_3:
      choice(soundList).play()
      direction2=0
    if event.key is K_4:
      choice(soundList).play()
      direction1=2
    if event.key is K_5:
      choice(soundList).play()
      direction1=-2
    if event.key is K_6:
      choice(soundList).play()
      direction1=0
This tutorial was written on: 03.10.2003 | Updated: 03.11.2003
:.Site.:.Menu.:
:// .site..news.
:// .tutorials..1.
:// .tutorials..2.
:// .projects.
:// .forums.
:// .gbook.
:// .links.