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)).

Monday, November 05, 2007

First steps in OpenGL with Python

I have always wanted to sink my teeth in OpenGL (ever since the days of the first Voodoo graphics cards). It always seemed to be the best tool for graphics programming on the PC (but boy, how I still miss my A1200's blitter chip!).

My main problem has always been my penchant for scripting languages ever since I switched from the Amiga (AmigaE and 68k assembler) to the PC. Which can be translated as: I never learned C, or C++ for that matter.

Python's been my latest love for the last few years now. First as a simple scripting language, then some GUI stuff with Tkinter, later Django came along and now I feel confident enough to tackle OpenGL.

As I started reading the red book (the online version for OpenGL 1.1 can be found here), I tried to convert some of the examples found there to Python, using pyglet (I like its easy way of setting up screens and windows compared to pygame's).

Here's a translation of example 2-5 (found near here):

from pyglet import window
from pyglet.gl import *

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

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

def display():
i = 0

glClear (GL_COLOR_BUFFER_BIT)
# select white for all lines
glColor3f (1.0, 1.0, 1.0)

# in 1st row, 3 lines, each with a different stipple
glEnable (GL_LINE_STIPPLE)

glLineStipple (1, 0x0101) # dotted
drawOneLine (50.0, 125.0, 150.0, 125.0)
glLineStipple (1, 0x00FF) # dashed
drawOneLine (150.0, 125.0, 250.0, 125.0)
glLineStipple (1, 0x1C47) # dash/dot/dash
drawOneLine (250.0, 125.0, 350.0, 125.0)
# in 2nd row, 3 wide lines, each with different stipple
glLineWidth (5.0)
glLineStipple (1, 0x0101) # dotted
drawOneLine (50.0, 100.0, 150.0, 100.0)
glLineStipple (1, 0x00FF) # dashed
drawOneLine (150.0, 100.0, 250.0, 100.0)
glLineStipple (1, 0x1C47) # dash/dot/dash
drawOneLine (250.0, 100.0, 350.0, 100.0)
glLineWidth (1.0)

# in 3rd row, 6 lines, with dash/dot/dash stipple
# as part of a single connected line strip
glLineStipple (1, 0x1C47) # dash/dot/dash

glBegin (GL_LINE_STRIP)
for i in range(0, 7):
glVertex2f (50.0 + (i * 50.0), 75.0)
glEnd ()

# in 4th row, 6 independent lines with same stipple
for i in range(0, 5):
drawOneLine (50.0 + (i * 50.0), 50.0, 50.0 + ((i+1) * 50.0), 50.0)


# in 5th row, 1 line, with dash/dot/dash stipple
# and a stipple repeat factor of 5
glLineStipple (5, 0x1C47) # dash/dot/dash
drawOneLine (50.0, 25.0, 350.0, 25.0)

glDisable (GL_LINE_STIPPLE)

# glFlush ()
# glFlush() is unnecessary, as flip() is called on window (ie double buffered window).

win = window.Window()
init()

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

Friday, December 29, 2006

English and the internet.


Remember, you don't need to be authentificated in order to use the English language.

Wednesday, December 06, 2006

Preventing collation errors while using MySQLdb and Python

MySQLdb is a great module to access MySQL databases. Nasty surprises sometimes do crop up though. Upon performing a simple query where two SELECT statements were UNIONed, the following error occurred:

_mysql_exceptions.OperationalError: (1267, "Illegal mix of collations (latin2_general_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation 'UNION'")

A bit of googling brought me to this excellent write-up of how someone with the same problems fixed them from the (PHP) client side.

I translated it to Python, and all UNIONs (up till now) work without a flaw.

Here's the code:

import MySQLdb
import MySQLdb.cursors # Import this so that DictCursors can be used.

# host, user, passwd and db to be defined by user ofcourse.
db = MySQLdb.connect(host = host, user = user, passwd = passwd, db = db, cursorclass=MySQLdb.cursors.DictCursor)

show = db.cursor()
q = "SHOW VARIABLES LIKE 'character_set_database'"
show.execute(q)
value = show.fetchone()['Value']

q = """SET NAMES '%s' """ % value
show.execute(q)


And that's all there is to it. Thanks to Juliette at adviesenzo.nl!