Loading images
Let's cover loading images from a file onto an OpenGL texture so that
we can display them on screen. We start by expanding on
gutil.py
from example 1.
1
2 import pygame
3
4 from OpenGL.GL import *
5 from OpenGL.GLU import *
6
7 def initializeDisplay(w, h):
8 pygame.display.set_mode((w,h), pygame.OPENGL|pygame.DOUBLEBUF)
9
10 glClearColor(0.0, 0.0, 0.0, 1.0)
11 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
12
13 glMatrixMode(GL_PROJECTION);
14 glLoadIdentity();
15 gluOrtho2D(0, w, 0, h);
16 glMatrixMode(GL_MODELVIEW);
17
18 #set up texturing
19 glEnable(GL_TEXTURE_2D)
20 glEnable(GL_BLEND);
21 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
We have added three lines to the initialize display function.
Line 19 enables texturing. Line 20 enables alpha
blending (transparency), and line 21 sets the function that OpenGL will
use for alpha blending.
24 def loadImage(image):
25 textureSurface = pygame.image.load(image)
26
27 textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
28
29 width = textureSurface.get_width()
30 height = textureSurface.get_height()
31
32 texture = glGenTextures(1)
33 glBindTexture(GL_TEXTURE_2D, texture)
34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
36 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData )
37
38 return texture, width, height
39
40
41 def delTexture(texture):
42 glDeleteTextures(texture)
The loadImage function takes a file name as an argument, and loads an
image file to a texture. Line 25 uses the PyGame image loader
to
open our file. Line 27 takes this image and exports it as a
string. Note the RGBA in the function call, which allows us
to
use images with an alpha channel.
Lines 29 and 30 capture the width and the height from the PyGame image
object.
Line 32 generates a new OpenGL texture. Line 33 sets it as
the
active texture. Lines 34 and 35 set the scaling methods that
OpenGL will use for this texture.
Line 36 is where we take the image data that we dumped to a string on
line 27, and insert the data into our texture. It is very
important to note that this step requires our image file dimensions to
be compatible with OpenGL texture dimensions. OpenGL texture
sizes must be powers of two, for example 16 x 16 or 128 x 512.
The size of our texture here is determined directly by the
size
of our image. So our image dimensions must be a power of two.
The final line of our function returns the texture id of our image, and
it's width and height.
On line 41 we have a delTexture function. It is important to
remember that OpenGL textures exist outside of Python's garbage
collection and memory management. The texture id that
loadImage
returns is not a Python object. It is only an id number.
So
if we stop using the texture before our program exits, we need to
explicitly free the memory in order to prevent memory leaks.
The function loadImage is all we really need to start displaying our
image. We can take the texture, bind it, and draw a textured
quad
using OpenGL. However, doing this by calling glBegin,
specifying
the texture and vertex coordinates, and calling glEnd involves ten
function calls. The function overhead for that many calls per
sprite is quite expensive, and if we want to be able to have large
numbers of sprites in a game, we need a more efficient way to render
our images. Here are two further functions added to gutil.py.
45 def createTexDL(texture, width, height):
46 newList = glGenLists(1)
47 glNewList(newList,GL_COMPILE);
48 glBindTexture(GL_TEXTURE_2D, texture)
49 glBegin(GL_QUADS)
50 glTexCoord2f(0, 0); glVertex2f(0, 0) # Bottom Left Of The Texture and Quad
51 glTexCoord2f(0, 1); glVertex2f(0, height) # Top Left Of The Texture and Quad
52 glTexCoord2f(1, 1); glVertex2f( width, height) # Top Right Of The Texture and Quad
53 glTexCoord2f(1, 0); glVertex2f(width, 0) # Bottom Right Of The Texture and Quad
54 glEnd()
55 glEndList()
56
57 return newList
58
59
60 def delDL(list):
61 glDeleteLists(list, 1)
The purpose of createTexDL, defined on line 45, is to improve rendering
speed. This
function takes a texture id, it's width, and it's heigh, and uses it
to create a display list that can be used to render the image to the
screen very quickly. Line 46 gets a list id from OpenGL.
Line 47 begins the definition of the list. Lines 48
to 54
specify the OpenGL commands to load the texture, and render it to the
screen. Line 55 ends the list, capturing the commands on
lines 48
to 54. The function returns the display list id, which we can
easily use to draw the image to the screen.
The delDL function is needed for the exact same reason as the
delTexture function. We want to be able to prevent memory
leaks
if we need to load objects and then forget them.
Now lets show an example of using our expanded gutil library.
example2a.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 def main():
10 pygame.init()
11 gutil.initializeDisplay(800, 600)
12
13 glColor4f(1.0,1.0,1.0,1.0)
14
15 done = False
16
17 cowTex, w, h = gutil.loadImage('data/cow.png')
18 cow = gutil.createTexDL(cowTex, w, h)
19 alienTex, w, h = gutil.loadImage('data/alien.png')
20 alien = gutil.createTexDL(alienTex, w, h)
21
22 while not done:
23 glLoadIdentity()
24 glTranslatef(100, 100, 0)
25 glCallList(cow)
26 glTranslatef(400, 400, 0)
27 glCallList(alien)
28
29 pygame.display.flip()
30
31 eventlist = pygame.event.get()
32 for event in eventlist:
33 if event.type == QUIT \
34 or event.type == KEYDOWN and event.key == K_ESCAPE:
35 done = True
36
37 if __name__ == '__main__':
38 main()
This new example requires two external image files located in a data
directory. One named cow.png and one named alien.png.
Line 17 loads our cow image, and gets it's texture id, it's width, and
it's height. Then on the next line we use this to create our
display list for drawing our cow. Lines 19 and 20 repeat the
process for the alien graphic.
Inside our main loop we have new code for displaying our images.
Line 23 resets our OpenGL rendering position. Line
24 tells
OpenGL we want to move to the x, y coordinates 100, 100. Line
25
uses our display list to draw our cow. Line 26 moves us an
additional 400 pixels up and 400 pixels to the right. Note
that
because we did not reset our position, we are now drawing at the
coordinates 500, 500. 27 is another display list call, this
time
to draw our alien.
Up to Intro
Back to Example 1
On to Example 2b