Tuesday, November 06, 2007

The Red Book, example 2-6

I had some trouble translating example 2-6 from the red book (the code resides under the enlarged grid, to be found a few lines below this link). But here it is:

from pyglet.gl import *
from pyglet import window

# The OpenGL context is created only when you create a window. Any calls
# to OpenGL before a window is created will fail.
win = window.Window()

def drawOneLine(x1 , y1, x2, y2):
glBegin(GL_LINES)
glVertex2f ((x1),(y1))
glVertex2f ((x2),(y2))
glEnd()

def display():
fly = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08]

halftone = [
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55]

glClear (GL_COLOR_BUFFER_BIT)
glColor3f (1.0, 1.0, 1.0)

# draw one solid, unstippled rectangle,
# then two stippled rectangles
glRectf (25.0, 25.0, 125.0, 125.0)
glEnable (GL_POLYGON_STIPPLE)

# convert the data to ctypes:
# Many thanks, Alex! (http://groups.google.be/group/pyglet-users/browse_thread/thread/10e304d4a5e77d97)
# Long version:
# array_type = (GLubyte * len(fly))
# fly = array_type(*fly)
# glPolygonStipple(fly)

# Short version:
glPolygonStipple( (GLubyte * len(fly))(*fly) )

glRectf (125.0, 25.0, 225.0, 125.0)
glPolygonStipple ( (GLubyte * len(halftone))(*halftone))

glRectf (225.0, 25.0, 325.0, 125.0)
glDisable (GL_POLYGON_STIPPLE)

# glFlush() unnecessary, as we call flip() during the main loop.
# glFlush ()

def init():
glClearColor (0.0, 0.0, 0.0, 0.0)
glShadeModel (GL_FLAT)

while not win.has_exit:
win.dispatch_events()
win.clear()
display()
win.flip()

As I have but a fleeting knowledge of how C handles variables, I was at a loss at how to pass an array of unsigned bytes to the glPolygonStipple() function. Help came via the people at the pyglet newsgroup. The solution boils down to (also see the comments in the code above):

  • Defining the array type (GLubyte * lenght of data list)

  • Converting the (elements of the) list to an array of the above defined type

  • Passing this array to the glPolygonStipple() function

As you see in the above code, these three steps can be easily factored into one single line: glPolygonStipple((GLubyte * len(fly))(*fly)).

No comments: