An Image Object
To make the new texture functions defined easier to use, I use an Image
object that abstracts away some of the details, and adds some
additional functionality.
Image.py:
1 from OpenGL.GL import *
2 import gutil
3 import os
4
5
6 class Image:
7 def __init__(self, texname=None):
8 filename = os.path.join('data', texname)
9 filename += ".png"
10
11 self.texture, self.width, self.height = gutil.loadImage(filename)
12 self.displayList = gutil.createTexDL(self.texture, self.width, self.height)
13
14
15 def __del__(self):
16 if self.texture != None:
17 gutil.delTexture(self.texture)
18 self.texture = None
19 if self.displayList != None:
20 gutil.delDL(self.displayList)
21 self.displayList = None
Lets begin by looking at the constructor and destructor methods of our class.
In order to simplify things, the class makes some assumptions about the
type of images that we want to load. Namely, it assumes that the
images are named with '.png' at the end, and are located in the 'data'
directory. You can see the code that handles these assumptions on
lines 8 and 9.
This means that in order to load an image named 'data/alien.png' we pass the class constructor the string 'alien'.
Line 11 loads the texture, and captures it's id, width and heigh. Line 12 then uses this data to get a display list id.
We have also defined a destructor that uses our cleanup functions.
With this in place, Python's memory management will automatically
take care of destroying any stray OpenGL objects we created.
Now lets take a look at the draw method.
24 def draw(self, pos=None, width = None, height = None, color=(1,1,1,1), rotation=0, rotationCenter=None):
25 glColor4fv(color)
26
27 if pos:
28 glLoadIdentity()
29 glTranslate(pos[0],pos[1],0)
30
31 if rotation != 0:
32 if rotationCenter == None:
33 rotationCenter = (self.width / 2, self.height / 2)
34 (w,h) = rotationCenter
35 glTranslate(rotationCenter[0],rotationCenter[1],0)
36 glRotate(rotation,0,0,-1)
37 glTranslate(-rotationCenter[0],-rotationCenter[1],0)
38
39 if width or height:
40 if not width:
41 width = self.width
42 elif not height:
43 height = self.height
44
45 glScalef(width/(self.width*1.0), height/(self.height*1.0), 1.0)
46
47
48 glCallList(self.displayList)
The method expands significantly on the glCallList technique that we
used in the last example. We add support of specifying the
drawing position, the drawing color, a rotation, and a width and
height for the image.
Lets start by looking at the arguments and how they are used.
Pos specifies the x, y coordinates that we will draw at. Line 27
shows that including values is optional. If a position isn't
specified, the texture will draw at whatever location OpenGL is
currently at. If you do give it a position, lines 28 and 29 reset
OpenGL, and then move to the coordinates to draw.
Color obviously specifes a 4 term color for the image. By default it is set to all white with 100% opacity.
Width and height are also optional arguments. If no arguments are
given, the sprite is rendered as it's default size. However if
you adjust the width or the height or both, the glScalef call on line
45 ensures that the image fills the correct number of pixels.
Rotations can be done by specifies the number of degrees to rotate the
image. RotationCenter is an optional set of x, y coordinates that
specify a position to rotate about. These coordinates are
relative to 0,0 being the bottom left corner of the image. If a
RotationCenter is not specified, the centre of the image is used.
You can see the logic for performing the rotation at the correct
offset on lines 31 through 37.
The last line of the draw function simply calls the display list for
the image, causing it to appear on screen with all the appropriate
effects applied.
Here is our example program, using the new Image class.
example2b.py:
1 #!/usr/bin/python
2
3 import gutil
4 import pygame
5 from pygame.locals import *
6 from OpenGL.GL import *
7
8
9 from Image import Image
10
11
12 def main():
13 pygame.init()
14 gutil.initializeDisplay(800, 600)
15
16 done = False
17
18 cow = Image('cow')
19 alien = Image('alien')
20
21 while not done:
22 cow.draw(pos=(100,100),width=128,height=128)
23 alien.draw(pos=(400, 400),rotation=-15,color=(.9,.3,.2,1))
24
25 pygame.display.flip()
26
27 eventlist = pygame.event.get()
28 for event in eventlist:
29 if event.type == QUIT \
30 or event.type == KEYDOWN and event.key == K_ESCAPE:
31 done = True
32
33 if __name__ == '__main__':
34 main()
As you can see, this new example is significantly simpler than the previous one, and it adds some new tricks.
Line 9 we import our Image class. Then on lines 18 and 19 we create new Image objects for our cow and alien images.
Line 22 draws the cow graphic at screen coordinates 100, 100, with a width of 128 and a height of 128.
Line 23 draws the alien at 400, 400, at it's actual size, with a -15 degree rotation, and a reddish tint.
Up to Intro
Back to Example 2a
On to Example 3a