Python Graphics

[ LiB ]

Python Graphics

Choosing a graphics toolkit may be the most difficult choice when creating a game. There are hundreds of graphic kits to choose from and each is very different in style and language. This chapter only covers a handful of the graphics libraries available for Python programming, and goes through samples in only a few of the available optionsmainly the popular kits available for developing cross-platform.

Specifically, more coverage of Tkinter is given in this section, as Tkinter comes bundled with Python, is cross platform, and is commonly used as a GUI for Python programs. Pygame is probably the most popular Python game library in use today, and Pygame graphic calls have already been covered in some detail. A few OpenGL samples in Python are also examined at the end of this chapter.


A number of commercial art tools are programmable with in Python scripts. Some of the more recognizable tools include Blender, Poser, Lightflow, and Softimage XSI. Each of these tools has a Python interface. Blender (i.e. gameBlender) uses Python as a scripting language, the Poser Pro pack includes a Python-scripting agent, Lightflow has a Python extension module, and Softimage is scriptable via Python.

For the aspiring developer, there are also many other graphic options available. Here, for starters, is a short list of Python GUI libraries and graphics kits:

  • The Standard Window Interface. STDWIN used to be the most commonly used GUI for Python, but is now largely unsupported. The library was meant to be a platform-independent interface to C-based Windows systems, but the module no longer exists in Python 2.0 or above, and I mention it mainly for legacy. It runs under UNIX and Mac, but was never ported to Windows .

  • The Wxpython library. Provides support for the wxWindows-portable GUI class library. Wxpythin uses the Lesser Gnu Public License and functions like a wrapper to the C++ wxWindows library. It is relatively cross platform, but not quite as portable as Tkinter.

  • The Pythonwin library. Pythonwin is also included in many standard Python distributions, but applications designed with it will only run on Windows. Pythonwin is a wrapper to the Microsoft Foundation Class Library, and provides features of the Windows user interface.

  • Wpy. An object-oriented, cross-platform class library system also based on the Microsoft Foundation Classes. Wpy is built to be simple and portable.

  • PyKDE. A set of Python bindings for the KDE classes written by Phil Thompson. PyKDE requires Sip to run.

  • PyGTK. A free software GUI toolkit that has a large number of widgets oriented towards the X Window System. PyGTK is distributed under the Lesser Gnu Public License and was developed for the GTK widget and GNOME libraries. The library is object-oriented and comes with lots of good samples.

  • GNOME Python. A set of bindings for the GNOME libraries that use PyGTK (which comes bundled with the package).

  • Wafepython. Wafe is short for Widget Athena Front End, and is a package for developing applications with high-level graphical user interfaces in Tcl. WafePython implements an interface between Tcl, the X Toolkit, the Athena Widget Set, the Motif Widget Set, and a few other classes and widget packages thrown in for good measure.

  • PyFLTK. FLTK stands for Fast Light Toolkit; it's a C++ GUI toolkit for UNIX, OpenGL and Win32. PyFLTK was originally created to build in-house apps for Digital Domain. Bill Spitzak is the original author and received permission from the company to distribute it under the Lesser Gnu Public License. Other developers have done more work on the toolkit since then, and the project has been moved to Sourceforge .

  • Fox Python. FXPy is a C++ toolkit for developing GUIs that runs on UNIX and Windows; it is distributed under the Lesser Gnu Public License. Fox's emphasis is on speed and ease of use. It uses techniques for increasing drawing speed and minimizing memory, and most controls can be built with a single line of code. Fox supports drag and drop, OpenGL widgets, 3D graphics, and tooltips.

  • Python X. An extension that binds Python together with Motif, which is a set of user interface guidelines set by the Open Software Foundation. Motif is actually over a decade old, and there are many books covering its use, but it has been somewhat in decline for a while.

  • The Python Computer Graphics Kit. A collection of Python modules for 3D computer-graphics images. The kit mainly focuses on Pixar's RenderMan interface, but some modules can also be used for OpenGL programs or non-RenderMan-compliant renderers.

  • Vpython. A free and open-source 3D programming library designed "for ordinary mortals ." The idea behind Vpython is ease of use and simplicity.

  • Zoe. A bare-bones OpenGL graphics engine written completely in Python. Zoe includes only basic 3D features, and focuses on creating 3D wire- frames for prototyping or rapid development.

  • The PyUI Library. An interface library written entirely in Python for Python. It can run on desktop Windows or in a 3D hardware-accelerated environment and is meant to be portable. PyUI was originally slated to build user interfaces for games . PyUI is owned by Sean Riley of Ninjaneering (see Chapter 5 for more information on Ninjaneering) and utilizes Python 2.1, Pygame, PyOpenGL, the Python Imaging Library, and the ActiveState win32 extensions.

  • PyQT. Qt for Windows is a C++ cross-platform GUI toolkit distributed by TrollTech, who have a free non-commercial version license and a pay commercial license. PyQT is a set of Python bindings to the C++ QT Toolkit, originally produced by the Kompany and now under River Bank Computing. The GUI toolkit runs on Windows, Mac OS X, and UNIX.



GUIs are created with graphical elements called widgets, which are typically scrollbars, buttons , text fields, etc. Widgets are normally found within a window, which con trols the layout of the widgets.

Python also has a few basic built-in tools for graphics and image handling. These are included under its Multimedia Services modules, which are listed in Table 4.3.

Table 4.3. Python Multimedia Graphic Services




Converting between RGB and other color systems


Manipulating raw image data


Determining the type of image contained in a file or bytestream


Reading and writing image files in SGI RGB format

The imageop module can operate on 8- or 32-bit pixel images and has methods for cropping, scaling, dithering, and converting the image at a raw level. Colorsys can be used to convert RGB, HLS, HSV, and YIQ color systems. Python's imghdr can recognize a number of different image formats (as shown in Table 4.4) and is also extendable to allow even more types.

Table 4.4. Image Formats


Image format


SGI ImgLib Files


GIF 87a and 89a Files


Portable Bitmap Files


Portable Graymap Files


Portable Pixmap Files


TIFF Files


Sun Raster Files


X Bitmap Files


JPEG data in JFIF Format


BMP Files


Portable Network Graphics

The Tkinter Library

In the last chapter you built a small display box using Tkinter. Here you'll explore GUI creation with Tkinter in more depth. As you recall, Tkinter is an object-oriented interface that works on multiple platforms and is designed to be extensible so that it can be used to import third-party widgets.


Tkinter comes with only a handful of standard widgets. Each widget has a standard set of methods and also supports a large set of general methods, so they are capable of a wide coverage. There is a lot more to widgets than what's listed in Chapter 3 (reprinted here as Table 4.5 for easy reference). This is because each of these components has its own place and use within a GUI, and therefore has its own components and methods associated with it.

Table 4.5. Tkinter Widget Components




Creates a button that triggers an event when clicked


Displays text or images


Creates a Boolean checkbutton


Creates a line that accepts keyboard input


Creates the outlying window's edge


Displays text as labels for components


Creates a list of options


Creates a multiple-selection display


Creates a pop-up or pull-down style menu


Creates a single option button


Creates a slider that can choose from a range


Creates a scrollbar for other components


Creates a multiple-line box that accepts user input


A widget container like Frame but with its own top-level window



TK is a toolkit that handles the creation of windows, GUI events (widgets), and user interaction. The TK toolkit is provided as an extension for Tcl. Tkinter is an interface to Tcl; without the interface it would take hundreds of lines of code to do even simple things like open a window or create a button.

Many languages use or are capable of using TK. Tkinter is Python's behind-the-scenes director of the TK GUI toolkit, and Tcl is the behind-the-scenes director that Tkinter uses to communicate to TK. Both TK and Tcl are open-source developments that are under development at scriptics (the Tcl developer exchange can be found at http://dev. scriptics .com).


Clickable buttons are probably the most widely used widget in any interface, and Tkinter has a many options available for button components; these are listed in Table 4.6.

Table 4.6. Button Properties




Sets the background color


Sets the foreground color


Displays a given bitmap as the button


Identifies the default button


Sets a foreground color used when button is disabled (grayed out)


Sets an image to display in the widget (precedes bitmap)


Defines the button state (as NORMAL , ACTIVE , or DISABLED )


Indicates whether the Tab key can be used to reach this button


Defines the text to display within the button


An offset applied on text displayed to identify which character must be underlined


Determines distance when text should be wrapped to the next line

Buttons also have their own special methods: flash() is a method which reverses and resets the foreground and background attributes, and invoke() is a method that executes the function defined in a command.

I used a button widget in the last chapter's GUI sample, inititated by the following code and looking like Figure 4.8 (a short sample is also given in this chapter's code section on the CD):

 Button(window, text='Exit', command=window.quit).pack(side=BOTTOM) 

This can be broken down into basic components. Button() is used to create the button, and the parameters placed within the Button() parentheses, ( window, text='Exit', command=win dow.quit ), define what the button can do. The pack() method extends Button() and defines where the button should be placed within the window, in this case side=BOTTOM .


The Canvas widget component is used to draw everything from arcs to bitmaps to polygons. It is used as a way to customize graphical items, and resembles an artist's blank canvas, ready to be painted . A canvas in Tkinter, of course, has its own properties; these are listed in Table 4.7. is given on the CD as a sample that produces a large widget surface, as shown in Figure 4.10.

Figure 4.10. Sample Canvas widget


Figure 4.9. The widget at work


Table 4.7. Canvas Properties




Creates an arc or an arc item


Creates a bitmap item


Creates an image item


Creates a line item


Creates a circle or ellipse at the given coordinates


Creates a polygon item (three or more vertices) with the given coordinates


Creates a rectangle item with the given coordinates


Creates a text item at the given position with the given options


Embeds a window widget to the canvas


A Checkbutton is basically a box that can either be checked or unchecked; an example is shown in Figure 4.11 and a sample is included in the CD's source code as . Checkbuttons can have an on value and an off value set for whether the box is checked, and have a handful of methods available, as shown in Table 4.8.

Figure 4.11. A sample checkbutton


Table 4.8. Checkbutton Methods




Selects the checkbutton and sets the value of the variable to onvalue


Reverses and resets the foreground/background colors


Executes a function defined by command()


Reverses the state of a button (i.e. off becomes on)


The Entry widget is designed to let users enter a single line of text within a frame or window. A sample is included on the CD.


A Frame widget is used to group , arrange, and organize other widgets. It uses rectangular screen areas and padding to put them into view for a GUI. A sample is included on the CD.


A Label widget is a box that displays text or images. The Label widget allows you to create and update these displays, and a demonstration is given as on the CD.


A Listbox widget creates lists of text items that can be selected by the user. Listboxes have three properties:

  • height. The number of rows in the list. Setting height to 0 allows listbox to automatically resize to the number of entries.

  • selectmode. Defines the type of list being created. This can be SINGLE , EXTENDED , MULTIPLE , or BROWSE .

  • width. The Number of characters in each row, which can also be automatically resized with the setting 0.

The Listbox widget also has a number of methods associated with it, as shown in Table 4.9.

Table 4.9. Listbox Methods




Deletes a given row, or the rows between the given row and lastrow


Gets the string that starts at the given row


Inserts the given string at the given row


Makes the row visible to the user


Clears the selection


Selects the rows starting at startrow and ending at endrow

A Listbox example is on the CD as .


There are three types of Menu widgets: pop-up, toplevel, and pull-down. There are also special menu widget item types such as radio menu items and check menu items. A sample menu is given as . Menus , of course, have their own methods, as listed in Table 4.10:

Table 4.10. Menu Methods




Adds a menu item


Creates a radio button menu item


Creates a check button menu item


Creates a new hierarchical menu


Adds a separator line to the menu


Adds a specified type of menu item


Deletes the menu items from startindex to endindex


Modifies a menu item


Returns the index number to the given menu item

These methods have their very own options available to them, as shown in Table 4.11.


Menubuttons can be used to display menus, but are in decline since the Menu widget has been expanded to include most of the Menubutton functionality.


Message is very similar to the Label widget, and is used to create a multiple line non -editable object that displays text.


Radio button widgets are multiple-choice buttons. Each group of radio buttons must be associated to the same variable, and each Radiobutton must represent a single value at any given time. Radiobuttons have their own properties:

  • command. Function to be called when the button is clicked.

  • variable. Variable to updated when button is clicked.

  • value. Defines the value that is stored in the variable when button is clicked.

Table 4.11. Menu Widget Method Options




A keyboard alternative to a menu option


Names the callback function when the menu item is selected


Adds a switch next to the menu options


Defines the text of the menu items


Switches color (with indicatorOn )


Defines menu item status ( normal , active , or disabled )


Values to be stored in the variable property


Values to be stored in the variable property


Creates a clickable separator at the top of the menu


Defines the index position of the character to be underlined


Variable used to store a value

Radiobuttons also have their own special methods:

  • flash(). Reverses forground and background colors.

  • invoke(). Executes command function.

  • select(). Selects the radio button.

A Radiobutton is shown in Figure 4.12 and a sample is included in the CD samples as .

Figure 4.12. A radio button



A scale widget is a graphical slider object that allows a user to select values from a scale. Scale has its own unique methods:

  • get(). Gets the current scale value.

  • set(). Sets the scale to a specified value. is included on the CD as a sample and Figure 4.13 displays the output of the sample code.

Figure 4.13. A Scale sample widget



A scrollbar widget is used to select from a vertical scroller and works with listbox , text , and canvas . Scrollbar in Tkinter has the same methods available as scale :

  • set(). Defines fractions between 0 and 1 that delimit the view.

  • get(). Returns the current scrollbar configuration settings.

A sample scrollbar is incuded on the CD ( Hello_Scrollbar ) and also illustrated in Figure 4.14.

Figure 4.14. A scale sample widget



Text allows the editing and formatting of multiple lines of text and has a number of available methods, as listed in Table 4.12.

Table 4.12. Text Methods




Deletes specified character(s)


Returns specific character(s)


Returns absolute value of an index


Inserts string at a specified index


Returns true if the text located at a given index is visible

There are also a few available attributes for text:

  • state. Sets text to editable or non-editable with the flags normal or disabled .

  • tabs. Provides a list of strings and identifies table stops on the Text widget.

Text widgets support bookmark positions , called Marks; the naming of regions of texts , called Tabs; and specific locations, called Indexes, to help them organize text. Each of these threeMarks, Tabs, and Locationshas access to specified methods.


The Toplevel widgets are directly managed by the window manager; its methods are listed in Table 4.13.

Universal Widget Methods

All widgets in Tkinter also have standard universal options for defining things they have in common. They all use a similar syntax, and are listed in Table 4.14.

There are also methods inherited from the base Tk classes that are provided for all Tkinter widgets, including the toplevel object created by the Tk() method. These always apply to the widget that makes the method call, and are listed in Table 4.15. Take notice of the idea of focus with these methods. The window or widget that is in focus is the one that is toplevel to the viewer.

Table 4.13. Toplevel Methods




Controls the relation between height and width


Used in X windows to define WM_CLIENT_MACHINE


Used in X windows to define WM_COLORMAP_WINDOWS


In X defines WM_COMMAND


Displays the window


Returns the window identifier


Sets the focus model


Changes the window's geometry


Adds given window to the window group


Defines a bitmap for when the window is iconified


Turns the window into an icon


Defines an icon bitmap for when the window is iconified


Defines an icon name for when the window is iconified


Defines a suggestion for where the icon goes when the window is iconified


Defines the icon window that should be used as an icon


Defines the maximum size for the window


Defines the minimum size for the window


Defines a flag different from 0, and tells the window manager not to add a title or borders to the window


Defines the position controller


Registers a function with a callback


Defines resize flags


Defines size controller


Returns the current state of the window, being normal, iconic, withdrawn, or icon


Defines the window title


Turns window into a temporary window for the given master which is automatically hidden


Removes the window from the screen

Table 4.14. Standard Tkinter Widget Options

Standard Widget Option



Defines height in number of characters or pixels


Defines width in pixels or number of characters

background or bg

Defines background color

foreground or fg

Defines foreground color


Defines border style


Defines color used to draw the highlight region when widget has keyboard focus


Defines color used to draw the highlight region when widget does not have keyboard focus


Defines highlight region width in pixels

borderwidth or bd

Width of widget relief border in pixels


Contains widget caption text, formatted by foreground and font


Sets LEFT , RIGHT , or CENTER for text captions


Can define font family, font size, and font values like bold, underline, and overstrike


Associates a widget with a Python function


Maps widget to a variable


Defines location of a widget within a window or of text within a widget


Defines padding on the x-axis to border


Defines the padding on the y-axis to border


Defines mouse pointer when moved over widget



Colors can vary from platform to platform. For instance, the Windows operating system has system color settings for windows in the Control Panel, while the UNIX X Window System keeps them in an xrgb text file. This could cause GUI color choices to change slightly (or radically ) from one operating system to the next.

Table 4.15. Tkinter Widget Methods




Returns a string that contains the current configuration value for a given option


Sets the values for one or more options


Same as config()


Destroys the widget


Sets the widget to a keyboard focus


As focus()


Returns the name of the window that contains the widget and has focus


Gives keyboard focus to the widget


Returns the identity of the window that has focus


Returns the window that last had focus


Returns the value of a Tkinter variable


Grabs all events for the entire screen for the widget


Releases grab on a widget


Returns none , local , or global depending upon the grab value set to a window


Returns all options available for a widget as a tuple


Moves a widget to the top of the window stack


Same as lift()


Moves a widget to the bottom of the windows stack


Activates the mainloop event


Quits the mainloop event


Sets a value to a given Tkinter variable


Processes all queued tasks


Processes all pending idle tasks


Returns the next widget that should have keyboard focus


Returns the previous widget that should have keyboard focus


Creates a local event that waits for the given Tkinter variable to change


Creates a local event that waits for the given widget to become visible


Creates a local event that waits for a given widget to be destroyed

There are also specific methods for all widgets that work within windows. For ease of reference, they begin with a winfo (short for Window Information). These methods are listed in Table 4.16.

Table 4.16. Widget Window Information Methods




Returns the number of cells in the widgets color map


Returns a list of widget instances


Returns the Tkinter class name for widget


Returns true if a widget's colormap is full


Returns the identity of the widget at the given x + y coordinates


Returns bit depth of the widget (8, 16, 24, or 32 bits per pixel)


Returns true if a Tk window corresponds to the given widget


Returns the result of the conversion of the given distance to the corresponding number of pixels (in floating point value)


Returns a string showing the widget coordination in pixels


Returns pixel height


Returns pixel width


Returns window identity


Returns true if a widget is mapped by the window system


Returns the name of the geometry manager


Returns widget name


Returns widget parent


Returns pathname of widget


Same as winfo_fpixels() except returns a regular integer instead of a floating point value


Returns the x coordinate of the mouse pointer in pixels (must be in widget window)


Returns the y coordinate of the mouse pointer in pixels (must be in widget window)


Returns minimum height required by widget to be displayed


Returns minimum width required by widget to be displayed


Returns the pixel coordinates of a widget's upper-left corner


Returns the pixel coordinates of a widget's upper-left corner


Returns the screen name for the current window


Returns the number of cells in the default color map for widget's screen


Returns the bit depth of the window target


Returns the height of a widget screen in pixels


Returns width of widget screen in pixels


Returns screen height but in millimeters


Returns screen width but in millimeters


Returns the default visual class used for widget's screen (i.e. grayscale, truecolor , staticcolor, and so on)


Returns the widget instance of the top-level window containing the widget


Returns the visual class used for the widget (grayscale, truecolor, staticcolor, etc.)


Returns x axis pixel coordinates corresponding to the widget's upper-left corner, relative to upper-left corner of the parent


Returns y axis pixel coordinates corresponding to the widget's upper-left corner, relative to upper-left corner of parent

Tkinter Geometry

Tkinter widgets have specific geometry management methods that are used to organize widgets in their area. These methods are organized in three classes that help a UI designer develop an interface. The methods are pack() , grid() , and place() .

Using these methods is fairly effortless. First you create a widget. In the last chapter you created a widget frame called window :

 Import Tkinter * window = frame() 

After you have a widget, you can simply and easily apply pack() , grid() , or place() directly on it:

 window.pack() window.grid() 

Using these three methods is very important in organizing a GUI interface, so I'll cover each one in the next subsections.


The pack() method is used to organize widgets in blocks before placing them in the parent widget. pack() adds a widget to a frame or window based on the order that the widgets are packed. If you don't specify how the widgets are to be packed, they are simply placed top to bottom in the available space. You can, however, specify placement with options like anchor or side . The pack() method has a few built-in methods, shown in Table 4.17.

Table 4.17. pack() Method Options




Expands a widget to use up available space


Defines how a widget should fill a parcel or frame


Used with fill to define space in pixels around an object


Used with fill to define space in pixels around an object


Defines space in pixels between widgets


Defines space in pixels between widgets


Defines where you want to place the widget ( chosen from TOP , BOTTOM , LEFT , and RIGHT )



The default is to use pixels to define measurement in pack() , but you can define different measurements, such as onscreen centimeters (c), onscreen millimeters (m), inches (i), and printer points (p). You specify which measurement to use by adding the letters to the options measurements:

 # this specifies padding to be in inches window.pack(padx=4i, pady=5y) 


The grid() method is used to organize widgets via a table within the parent widget. grid() creates a grid pattern (go figure) within a frame, and then allocates space to each cell in the grid to hold a widget. This grid starts are location (0,0) at the top left of the window. Grid() has a few methods, outlined in Table 4.18.

Table 4.18. grid() Method Options


Use Example


Specifies the column number


To make a widget span multiple (default is 1 column)


Specifies the row number


To make a widget span multiple rows (default is one row)


The place() method is used to place widgets in specific a specific position in the parent widget. place() allows you to set the exact position and size of each widget, in terms of absolute or relative coordinates. The place() method can use the options listed in Table 4.19.

Table 4.19. place() Method Options




Defines coordinates by (by compass: N , S , E , W , NE , NW , SE , SW , or CENTER ). Default value is NW




Defines widget height in pixels


Places widget in a position relative to the given widget ( in_ )


Defines relative height in reference to in_


Defines relative width in reference to in_


Defines relative position in, reference to in_


Defines relative position in reference to in_


Defines widget width in pixels


Define absolute position of widget on y-axis, default 0


Define absolute position of widget on x-axis, default 0

Tkinter Events

Events in Tkinter are user events like keyboard presses and mouse movements. Tkinter handles events by creating bindings for specific objects. You can bind events to a widget, to the widget's Toplevel window, to a widget's class, or to an entire application.

Once an event has been bound to a widget, you specify a callback, which is a function that is called when the event happens. Let's say you had a function called My_Event :

 def My_Event():         //does something here 

Let's say you want My_Event to be called by a widget button called My_Button :

 My_Button = Button() 

The My_Button widget can call My_Event by simply including a command option on one line:

 My_Button['command'] = My_Event 

You can assign events to keyboards and mouse presses as well, as shown in Table 4.20 and Table 4.21.

Table 4.20. Tkinter Mouse Events



<Button -1>

Mouse button (left) is pressed over widget

<Button -2>

Mouse button (middle) is pressed over widget

<Button -3>

Mouse button (right) is pressed over widget

<B1 Motion>

Mouse is moved with the button held down (dragged)

<ButtonRelease -1>

Mouse button is released

<Double Button - 1>

A double click


Mouse pointer enters widget


Mouse pointer leaves widget

Table 4.21. Tkinter Keyboard Events



<Alt -x>

Pressed Alt and another key

<Control -X>

Pressed Ctrl and another key


Pressed the Esc key


Press any key (carries the character pressed via a callback)


Pressed the Enter key

<Shift -X>

Pressed Shift and another key

The object that originated the callback exposes the attributes for events. These attributes are listed in Table 4.22.

Table 4.22. Tkinter Event Attributes




Character code of pressed key


New height of a widget in pixels


Key code of a pressed key


Key symbol of a pressed key


The mouse button number associated with an event (usually 1, 2, or 3)


The event type


The widget instance


New width of a widget in pixels


The current position in pixels of the mouse on the x-axis


The current x-axis position of the mouse in pixels relative to the upper-left corner of the screen


The current position in pixels of the mouse on the y-axis


The current y-axis position of the mouse in pixels relative to the upper-left corner of the screen



For Tkinter mouse events, you will often find <Button 1 > replaced with <ButtonPress-1> or <1> , all of which are correct syntactically. These changes work for the middle and right-side buttons as well.

For Tkinter keyboard events, most keys can be represented by placing them within less than and greater than symbols ( <F1> , <Cancel> , and <End> , for example).

There are also methods used to handle a callback by binding a Python function or method to an action that can be applied to a widget. These are shown in Table 4.23.

Table 4.23. Tkinter Event Callbacks




Alarm callback called after given time in milliseconds


Cancels an alarm callback


When the system is idle, registers a callback

bindtags ()

Returns the search order used by widget


Defines the callback that must be associated to a given event


Defines the callback that must be associated to a given event at the application level


Defines the callback that must be associated to a given event at the given widget class


Widget is resized or moved to a new location


Removes bindings for the given event


Removes bindings at the application level


Removes bindings for the given event at the given widget class

Finally, Tkinter has protocols to handle events that communicate between the window manager and the GUI. This allows an application to intercept messages from the system and act accordingly . These protocols were original established for the X system, but Tk can handle events on multiple platforms. The syntax to bind a protocol to a handle event is as follows :

 widget.protocol(protocol, handler) 

In order for the widget to intercept a system message it needs to be on the Toplevel. The handler is almost always a function.

Tkinter Images

Tkinter uses the image class as a foundation to display graphic objects. Graphic objects Tkinter can display include both bitmap ( BitmapImage ) and GIF ( PhotoImage ) images. The functions image_names and image_types are used to handle all the images within the image class. The first returns a list containing the names of all available images, and the second returns a list that contains all the existing types that were created.

Images, once created, provide a handful of methods: image.width() , image.type() , and image.height() .


BitmapImage is used to display bitmap images on widgets. In Tkinter, however, a bitmap not a .bmp format image. Bitmaps are actually two color images (well, two colors and a transparency mask to be precise) and have the options listed in Table 4.24.

Table 4.24. BitmapImage Options




Returns value of the given option


Changes image options


Changes image options


Returns height in pixels


Returns width in pixels


Returns the bitmap string

These options have methods available to them, listed in Table 4.25.

Table 4.25. BitmapImage Option Methods


Used For


Background color


String to be used instead of a file


File to be read


Foreground color to be used


Specifies the file handler to be used


String that defines the contents of the mask


Specifies mask file


Gives image dimensions


Gives image dimensions


PhotoImage is used for displaying full color images; it supports GIF and PPM files and has attributes as listed in Table 4.26.

Table 4.26. PhotoImage Attributes




String to be used instead of a file


File to be read





The PyOpenGL Library

PyOpenGL is an OpenGL widget written by a large group of developers, including David Ascher, Mike Hartshorn, Jim Hugunin, and Tom Schwaller. PyOpenGL includes OpenGL bindings for Python created using the Simplified Wrapper and Interface Generator (SWIG) and distributed under open source licenses. It supports OpenGL v1.0, OpenGL v1.1, GLU, GLUT v3.7, GLE 3, WGL 4, and Togl (Tk OpenGL widget). PyOpenGL is also interoperable with Tkinter, wxPython, FxPy, PyGame, and Qt and a large number of other external GUI libraries for Python. It has a very active following and a regularly updated sourceforge project page at

OpenGL has the reputation of being difficult to learn. Hey, there are reasons why they pay game developers the big bucks! Python's version of OpenGL is no different than any other version, and OpenGL looks pretty similar no matter what language you're playing with.

The reason OpenGL is considered difficult to pick up is because three-dimensional graphics programming can be a fairly difficult subject just on its own. Since OpenGL is fairly difficult to master, this section covers just a few examples. If you discover, as many programmers do, that OpenGL is your calling, then I recommend that you pick up OpenGL Game Programming by Kevin Hawkins and Dave Astle.

Using OpenGL in Python is quite an advantage over other languages, however, because Python and Pygame make several complex steps much easier. For instance, I use the window in these examples to open up a window for displaying graphics. This could take dozens of lines of code in a nonhigh-level language, but it only takes two in these examples. You also do not have to worry about freeing and releasing memory for all of the complex graphics calls and routines. However, having no control over memory allocation and de-allocation can cause problems.



OpenGL is a standard graphics library originally created by Silicon Graphics. Back then it was called GPL, and only ran on SGI hardware. SGI eventually turned their technology into an open standard and licensed it to different machines. OpenGL may be the premier development tool for developing portable 2d and 3d applications, and it has also been a standard since the early 1990s.

OpenGL is free for application and game designers. It is an owned technology, but the licensing applies to venders of hardware (i.e., the graphic card makers ) that wish to utilize the technology, not the software developers. SGI is currently working towards modifying the license into a true open source license. This makes OpenGL very popular among game developers, and many commercial games have used it, from Activision's Quake , to Blizzard's Diablo , to Bioware's NeverWinter Nights .

Installing PyOpenGL

PyOpenGL needs a handful of dependencies in order to access all of its functionality. Luckily, most of these will already be installed if you've been playing with the code in this chapter. PyOpenGL needs Python 2.2 or higher, Tcl/Tk, OpenGL, GLU (which should come pre-installed on most modern machines and with most modern graphics card), the OpenGL Utility Toolkit (or GLUT for short), and Numeric Python.

The OpenGL Context may also require a few dependencies, depending on the platform. Those dependencies that are freely distributable are on this book's CD, under \PYTHON\PYOPENGL\DEPENDENCIES, except for Numeric Python, which has its own folder (\PYTHON\NUMERIC PYTHON). The standard binary installers for PyOpenGL are located on the CD under \PYTHON\PUOPENGL. The source and project page for PyOpenGL can be found at Sourceforge, which is where you will want to look for the latest updates and news:

Using PyOpenGL

There are four libraries to PyOpenGL, each of which is normally imported separately:

  • GL. The basic, primitive library.

  • GLU. Short for GL utilities; includes more advanced commands than GL.

  • GLX. GL for X_Windows.

  • GLUT. GL Utilities Toolkit, which has even more sophisticated windowing features.

For these samples you will be using both GL and GLU:

 from OpenGL.GL import * from OpenGL.GLU import * 

To make things easier, you will also be using bits of the Pygame library:

 import pygame from pygame.locals import * 

First a small program creates a PyOpenGL Window with a graphic on a Win32 platform. This first program, labeled in this chapter's code section on the CD, also sets the precedent for each PyOpenGL example that follows, so pay attention!

Presenting a Window in PyOpenGL

If you look at the sample code, the first thing you do after giving Python and Pygame access to the PyOpenGL libraries through import statements is to declare a couple of variables , like so:

 rquad = 0.0 xrot = yrot = zrot = 0.0 textures = [0,0] 

These are variables you'll use in later examples, not for this first simple one, so you can ignore them for now.

After the variables you define how to size the window or PyOpenGL scene. Do this by creating a windowsize function. This function will be called to set up the window or scene at least once when the program is first run, and when it is called, it will be given the height and width you want the window to be:

 def windowresize((width, height)):     glViewport(0, 0, width, height)     glMatrixMode(GL_PROJECTION)     glLoadIdentity()     gluPerspective(45, 1.0*width/height, 0.1, 100.0)     glMatrixMode(GL_MODELVIEW)     glLoadIdentity() 

The first command in windowresize is glViewport . This command resets the current view.

The glMatrixMode(GL_PROJECTION ) line then sets up the projection matrix, which is responsible for adding perspective. glMatrixMode is defined by the next two commands, in which the scene is set and the perspective is defined. The command that follows is glLoadIdentity() , which resets and restores the projection matrix to its original state.

Objects on the screen that are meant to be far away need to appear smaller in order to create realistic 3D, so the perspective is then defined with gluPerspective . In this example, the perspective is calculated by a 45-degree viewing angle based on 1 times (1.0*) windowsize 's height and width. 0.1 and 100.0 are the starting and ending points for how deep the screen can go, and how many layers the screen can have.

Finally, you use glLoadIdentity() a second time to turn attention to the projection matrix and reset it.

Initializing PyOpenGL

After defining a three-dimensional window, you can then create a function that initializes PyOpenGL. You need to establish what color the screen starts out as, the depth buffer, and whether to use smooth shading, as well as a number of other possible PyOpenGL features. Do this with an initialize command:

 def initialize():     glShadeModel(GL_SMOOTH)     glClearColor(0.0, 0.0, 0.0, 0.0)     glClearDepth(1.0)     glEnable(GL_DEPTH_TEST)     glDepthFunc(GL_LEQUAL)     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 

In initialize , you use glShadeModel(GL_SMOOTH) first to ask PyOpenGL to use smooth shading (smooth shading is simply one way of blending colors and lighting when rendering a polygon). Next you use glClearColor , which sets the color of the window screen when it is clear.

PyOpenGL takes in four numbers when you declare a color. The first three represent the primary colors red, green, and blue, and the last is the alpha (transparency channel). Each number can range from 0.0 to 1.0; the lower the number, the darker the intensity, the higher the number, the brighter the intensity. The numbers must be in order of Red, Green, Blue, and Alpha. You can create different colors by mixing these primary colors. Black would be (0,0,0,0), white would be (1,1,1,0), and yellow would be (1,1,0,0) . Of course, the last number is the alpha or transparency.

After setting the screen color you set up the depth buffer. The depth buffer keeps track of how many layers deep the screen goes, and you need to have depth in order to have any sort of 3D. The depth buffer actually keeps track of which objects are in front and which are in back, so it knows how to draw the screen in the proper perspective. There are three commands associated with the depth buffer in our initialize function: glClearDepth , glEnable , and glDepthFunc .

glClearDepth specifies the depth value used when the depth buffer is cleared. The glEnable command is used to enable various PyOpenGL capabilities. In this case, it is enabling depth testing, which will allow initialize to do depth comparisons and update the depth buffer. glDepthFunc specifies the function used to compare each incoming pixel depth value with the depth value present in the depth buffer. LEQUAL is short for Less than or Equal to, and sets glDepthFunc to pass the incoming depth value if it is less than or equal to the present value.

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ) is a long command, but it's basically only a way of telling PyOpenGL to please use the best corrective perspective and the highest-quality view when there is room for interpretation.

Drawing a Square

Our third function is the code that actually draws the display, so let's call it drawgraphics() . This function will actually display everything that goes onto the screen, so it will be doing most of the work in each example.

 def drawgraphics():     glClear(GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT)     glLoadIdentity()     glTranslatef(0.0, 0.0, -5.0)     glBegin(GL_QUADS)     glVertex3f(-1.0, 1.0, 0)     glVertex3f(1.0, 1.0, 0)     glVertex3f(1.0, -1.0, 0)     glVertex3f(-1.0, -1.0, 0)     glEnd() 

First you glClear to clear the screen to a color, clear the buffer, and then reset with glLoadIdentity . glLoadIdentity actually moves you to the center of the screen, which is 0,0 on the x- and y-axis. Left and down are negative numbers, and right and up would be positive numbers; see Figure 4.15.

Figure 4.15. Three-dimensional space labeled by X,Y, and Z


The glTranslatef() command produces a translation of the current matrix by multiplying it by the x, y, and z coordinates given to it. This sounds confusing, but all it really does is change the drawing point from the current view to someplace else. In this case, you do not change the glTranslatef() x or y coordinates (leaving them at 0,0) but you do give a -5.0 for the z-axis, which basically pushes the matrix back five screen depths. If you didn't push the matrix back, what you drew would be too close to the front of the 3D space for you to see it. Basically, glTranslatef() is the command that moves along the x-, y-, and z-axes. For instance, glTranslatef(1.5, 0.0, and 6.0) would mean to move left 1.5 units and into the screen depth by 6 units.



When you use glTranslatef() , you are not mov ing coordinated relative to the center of the screen, you are actually moving glTranslatef() relative to wherever it currently is. If you left glTranslatef() at the top right corner of the screen with the last command, that is where it will still be when you use it later. This means you need always keep track of its current position.

glBegin tells PyOpenGL that you want to start drawing, and ( GL_QUADS ) tells PyOpenGL that you want to draw a square or four-sided shape of some sort. You use glVertex() to tell PyOpenGL where the four points of your square shape are located on the x-, y-, and z-axes, and glEnd() means you are done drawing and that there are no more points. The first glVertex() number is is the first point of the square (and the x-axis, if you are drawing a polygon). The second number is the y-axis, and the third number is the z.

You have three usable functions; now you just have to set them up in a main loop.

 def main():     # Define any variables     video_flags = OPENGLDOUBLEBUF     # Initialize Pygame     pygame.init()     pygame.display.set_mode((640,480), video_flags)     # Call our windowsize and Initialize functions     windowsize((640,480))     initialize()     #set frames to 0 before loop starts     frames = 0     # Have pygame keep track of time     ticks = pygame.time.get_ticks()     # while loop that draws and looks to quit     while 1:         event = pygame.event.poll()         if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):             break           # Draw our fun graphics          drawgraphics()          pygame.display.flip()          frames = frames+1 if __name__ == '__main__': main() 

There is actually quite a bit going on here. First, you define video_flags to be OpenGL and double-buffered; these are calls you need to make to Pygame in order to render OpenGL correctly. Then you initialize Pygame with its init() method and set the display to 640x480 with your video flags.


Double Buffering

Drawing and redrawing screens and images can be time- and processor-consuming, and game programmers have developed many tricks for increasing the speed it takes to render drawings. One of these tricks is called double buffering , and is very common when animating. Double buffering is so common, in fact, that most modern game and animation libraries have built-in support for flags for using the technique. Can you believe that programmers used to have to create their own buffers by hand? Talk about Dark Ages!

Normally, when an image is redrawn, it is simply redrawn in place on the screen. In double buffering, the image is redrawn ahead of time in a buffer or a hidden area of the screen or memory, and then, when it is time to re-display, the buffer is simply copied to the screen. In reality, a complex animation or sequence may have dozens of unseen layers constantly loading with the graphics that will display seconds later.

Then you call the windowsize function with the same display size (640x480) and the initialize function that initializes PyOpenGL. You set up a baseline frame variable (equaling 0) and then you ask Pygame to use pygame.get.ticks to keep track of time in milliseconds.

The actual work happens in the while loop. First, use Pygame's event.poll() function to see, via keyboard input and an if statement, whether the user wants to quit. Then call the draw graphics function, which draws the square.

pygame.display.flip() updates the display each time it is called. pygame.dipsplay knows that you are using OpenGL and double buffering because of your earlier video flags, so it updates the entire display by swapping the current view with the new ones it has drawn and stored in memory (this is called a gl buffer swap ). Then you update your frames so that you know how many times the while loop has looped, and finally you initiate main with a standard Python if line.

Whew! If you run you'll see a white square open in a 640x480-pixel Pygame window, similar to that in Figure 4.16.

Figure 4.16. displays a square rendered in PyOpenGL and displayed within a Pygame window


Setting the Color of an Object

Now that you have a baseline, let's look at what else you can do with PyOpenGL. Let's try giving the square a color. You can use the glColor3f() command, which also takes in three commands, one each for red, green, and blue intensity values: glColor3f(r, g, b,) . PyOpenGL keeps these standards consistent across commands, so the colors have a range from 0.0 to 1.0 and work exactly the same as if you were setting up the screen background color with glClearColor3f() .

Turning on glColor3f is like switching to a different-colored pen. When you switch to red, everything you draw after that point is red. Then, if you switch to another color, everything you draw after that is drawn in the new color. To make your square a Python green, you simply need to add the glColor3f command in your drawgraphics() function before you begin drawing with glBegin(GL_QUADS) , like so:

 def drawgraphics():     glClear(GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT)     glLoadIdentity()     glTranslatef(0.0, 0.0, -5.0)     #Adding color to our square     glColor3f(0.1, 0.9, 0.5)     glBegin(GL_QUADS)     glVertex3f(-1.0, 1.0, 0)     glVertex3f(1.0, 1.0, 0)     glVertex3f(1.0, -1.0, 0)     glVertex3f(-1.0, -1.0, 0)     glEnd() 

Now when you run this program (labeled on the CD), you will see a green square just like that in Figure 4.17. Notice that the polygon fills in the entire surface with the colors you've drawn. This is called smooth coloring .

Figure 4.17. Coloring in a surface with glColor3f()


Rotation and Movement

Now that you can color the square, let's try to rotate it. To do so, you need to add a bit to the drawgraphics function. First, make use of the rquad ( rquad is short for rotate quad ) variable by declaring it a global and then calling the glRotatef() function. Use a variable for rotation so that you have fine-grain control over the movement.

glRotatef(angle, x, y, z) produces a rotation of a given angle in degrees over a given vertices given in x, y, and z coordinates. The command takes four arguments: Angle , X vecto r, Y vector , and Z vector . Angle is a number that represents how much to spin the object. The x, y, and z vectors represent the vector around which the rotation will occur. For instance, (1,0,0), describes a vector that travels in the direction of 1 unit along the x-axis.

The current matrix (remember it's all about glMatrixMode ) is changed by this rotation. Set up the rotation by adding one line that calls glRotate() on your square using the rquad variable as the angle and rotating on the x-axis:

 def drawgraphics():     glClear(GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT)     glLoadIdentity()     glTranslatef(0.0, 0.0, -5.0)     # Set up rquad for rotation, only real difference     global rquad     glRotatef(rquad, 1.0, 0.0, 0.0)     glColor3f(0.1, 0.9, 0.5)     glBegin(GL_QUADS)     glVertex3f(-1.0, 1.0, 0)     glVertex3f(1.0, 1.0, 0)     glVertex3f(1.0, -1.0, 0)     glVertex3f(-1.0, -1.0, 0)     glEnd() 

And then at the end of drawgraphics you update rquad so that the drawing of the square continually rotates:

 # And update rquad for movement     rquad+= 0.1 

This creates a rotating flat square, as illustrated in Figure 4.18 (the source is on the CD as .

Figure 4.18. A flat plane rotates along its x-axis


By playing with the rquad variable, you can change how many degrees the plane rotates on the x-axis. You can make the plane spin faster or slower, backwards or forwards, by changing the values associated with it.

Moving from Flat to 3D

You have already done most of the work for displaying three dimensions. Let's say you wanted to change your flat plane to a cube. GL_QUAD is actually capable of displaying a cube object; you just need to tell it where the other vertices for the other five flat planes should go. This becomes a pixel-plotting problem; it is shown in Figure 4.19.

Figure 4.19. A cube and points for each side are mapped out in 3D space


Once you know where each pixel belongs, you can feed the location to GL_QUAD , which fills in each surface for you:

 # Front Face     glVertex3f( 1.0, 1.0,-1.0)     glVertex3f(-1.0, 1.0,-1.0)     glVertex3f(-1.0, 1.0, 1.0)     glVertex3f( 1.0, 1.0, 1.0)     # Back Face     glVertex3f( 1.0,-1.0, 1.0)     glVertex3f(-1.0,-1.0, 1.0)     glVertex3f(-1.0,-1.0,-1.0)      glVertex3f( 1.0,-1.0,-1.0)     # Top Face     glVertex3f( 1.0, 1.0, 1.0)     glVertex3f(-1.0, 1.0, 1.0)     glVertex3f(-1.0,-1.0, 1.0)     glVertex3f( 1.0,-1.0, 1.0)     # Bottom Face     glVertex3f( 1.0,-1.0,-1.0)     glVertex3f(-1.0,-1.0,-1.0)     glVertex3f(-1.0, 1.0,-1.0)     glVertex3f( 1.0, 1.0,-1.0)     # Right face     glVertex3f(-1.0, 1.0, 1.0)     glVertex3f(-1.0, 1.0,-1.0)     glVertex3f(-1.0,-1.0,-1.0)     glVertex3f(-1.0,-1.0, 1.0)     # Left Face     glVertex3f( 1.0, 1.0,-1.0)     glVertex3f( 1.0, 1.0, 1.0)     glVertex3f( 1.0,-1.0, 1.0)     glVertex3f( 1.0,-1.0,-1.0) 

Now the cube has six sides. PyOpenGL automatically draws them in a counter-clockwise orderthe first point is top-right, the second point is bottom-right, and so on until completely around the given plane. The rotation is already built-in, and the MatrixMode automatically knows to update each side as it rotates; check out on the CD and Figure 4.20.

Figure 4.20. The flat plane becomes a full rotating cube


Let's say you wanted to speed up and twist your rotating cube around a bit more. It's easy to fiddle with MatrixMode, especially since you've thought ahead and included a number of variables with which to do it:

 # Now we use all of these # x,y, and z rots are the rotations on each axis xrot = yrot = zrot = 0.0 

These variables, xrot , yrot , and zrot , can be used to rotate the cube in a new way on the x-, y-, and x-axes. Do so by adding a few lines to the top of drawgraphics :

 global xrot, yrot, zrot     glClear(GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT)     glLoadIdentity()     glTranslatef(0.0, 0.0, -5.0)     global rquad # not used for now     glRotatef(xrot,1.0,0.0,0.0)     glRotatef(yrot,0.0,1.0,0.0)     glRotatef(zrot,0.0,0.0,1.0) 

And then add a few lines to the end of drawgraphics :

 # Use XYZ to rotate - speed it up a bit     xrot = xrot + 0.9     yrot = yrot + 0.9     zrot = zrot + 0.9 

This will cause your cube to rotate quicker and also spin on aother axis.

Adding Textures

In your final PyOpenGL tutorial you'll open and use a local texture image instead of having PyOpenGL simply color the cube; this is illustrated in Figure 4.21. The full code is listed in in the Chapter 4 code section on the CD.

Figure 4.21. A textured cube spins around each axis


First you will make use of import os . A texture will then have to be loaded from outside of Python, and your program will need to understand how to navigate through different directories and pull files from its native operating system.

You will also finally be using the texture variables you initialized early on:

 # textures for loading the .bmp image textures = [0,0] 

You will be using textures[] for loading the .bmp you will be using for texture. The first thing you need is a new function that opens up the .bmp file:

 # New function to find, load, and use the texture def loadtextures():     # Need to find and load the texture     point_to_file = os.path.join('dtcfe.bmp')     texture_surface = pygame.image.load(point_to_file)     texture_buffer = pygame.image.tostring(texture_surface, "RGBX", 1) 

First, point_to_file uses the os module's os.path.join to point to the .bmp you want to usein this case it is the dtcfe.bmp file found on the CD with the code samples. The next two commands use Pygame methods to load the .bmp image to a new surface (texture_surface ) and then copy the image into a larger string buffer (texture_buffer ). Specifying RGBX tells Pygame that the texture should be 32-bit padded RGB data. This turns the .bmp image into an actual texture.

With Pygame, your textures must be at least 64x64 pixels, and shouldn't be more than 256x256 pixels. Textures need to be sized in height and width to the power of 2 (if the textures are 64x64, 128x128, or 256x256, they do not need to be resized, otherwise they do). These are of course the standard defaults for textures and are changeable , but not without more advanced programming.

Now that Pygame has the texture, you hand it over to OpenGL. First you need to specify that the texture is two-dimensional with GL_TEXTURE_2D , and then you need to bind it to a texture[] array that will hold any and all textures your program needs:

 glBindTexture(GL_TEXTURE_2D, textures[0]) 

glTextImage2D is a PyOpenGL command that specifies a two-dimensional texture. You feed it several values, including the texture surface, width, and height (using the get_width() and get_height() methods). Then you specify that the texture is two-dimensional with GL_TEXTURE_2D , explain how the color format is organized with GL_RGBA , define the data format used to store the texture data with GL_UNSIGNED_BYTE , and finally, you give glTextImage2D() the actual data of the texture itself, texture_buffer , which you defined with Pygame:

 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texture_surface.get_width(), texture_sur- face.get_height(), 0,                    GL_RGBA, GL_UNSIGNED_BYTE, texture_buffer ); 

Whewthat's our longest one-liner yet. The last step in loading a texture is to tell PyOpenGL what filtering to use when the image is stretched or altered on the screen. To do so, use PyOpenGL's built-in glTexParameterf() , which simply defines the options to use when texture mapping. The MIN and MAG filters specify texture magnification, and GL_NEAREST asks PyOpenGL to grab the nearest pixel when redrawing the GL_TEXTURE_2D image:


Now that you can load the .bmp image and turn it into a texture, you need to make PyOpenGL use the texture on each side of the cube instead of filling in the sides with glColor3f() .

Drawing a textured cube is quite a bit different from drawing colored cubes. Most of the gl functions are the same but the glBindTexture command we used to load textures sets the texture we want to use, much like glColor3f() set the pen to a specific color:

 glBindTexture(GL_TEXTURE_2D, textures[0]) 

To map the texture correctly into a specific side of the texture, you need to make sure the top-right of the texture is mapped to the top-right of the side; same with the bottom-left. Each corner needs to be mapped using the glTexCoord2f() , command like so:

 glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,  1.0) 

The glTexCoord2f command is designed to map out textures in two dimensions. Once you get the hang of using the command it is as easy to use as glColor , there is just an added complexity to each of the cube's mapped points:

 glBegin(GL_QUADS)     # Front Face     glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0,  1.0)     glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0,  1.0)     glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)     glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)     # Back Face     glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0)     glTexCoord2f(1.0, 1.0); glVertex3f(-1.0,  1.0, -1.0)     glTexCoord2f(0.0, 1.0); glVertex3f( 1.0,  1.0, -1.0)     glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0)     # Top Face     glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0, -1.0)     glTexCoord2f(0.0, 0.0); glVertex3f(-1.0,  1.0,  1.0)     glTexCoord2f(1.0, 0.0); glVertex3f( 1.0,  1.0,  1.0)     glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0)     # Bottom Face     glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0)     glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0)     glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0,  1.0)     glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0,  1.0)     # Right face     glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0)     glTexCoord2f(1.0, 1.0); glVertex3f( 1.0,  1.0, -1.0)     glTexCoord2f(0.0, 1.0); glVertex3f( 1.0,  1.0,  1.0)     glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0,  1.0)      # Left Face     glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0)     glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0,  1.0)     glTexCoord2f(1.0, 1.0); glVertex3f(-1.0,  1.0,  1.0)      glTexCoord2f(0.0, 1.0); glVertex3f(-1.0,  1.0, -1.0)     glEnd(); 

The result of this code ( is illustrated in Figure 4.21.

[ LiB ]

Game Programming with Pyton, Lua and Ruby
Game Programming with Pyton, Lua and Ruby
Year: 2005
Pages: 133 © 2008-2017.
If you may any questions please contact us: