Putting Text on screen
When combining pygame and OpenGL for game making, there are some
challenges to putting text on the screen. This is how I do it.
Lets start with adding a function to gutil.py:
64 def loadText(text, size = 12, color = (0,0,0), font = None, antialias = True):
65
66 fontObj = pygame.font.Font(font, size)
67 image = fontObj.render(text, antialias, color)
68 height = image.get_height()
69 width = image.get_width()
70 h = 16
71 while(h < height):
72 h = h*2
73 w = 16
74 while(w < width):
75 w = w*2
76
77 label_texture= glGenTextures(1)
78 glBindTexture(GL_TEXTURE_2D, label_texture)
79 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
80 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )
81
82 emptyList = "\x00" * w*h*4
83 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, emptyList )
84
85 textureData = pygame.image.tostring(image, "RGBA", 1)
86 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.get_width(), image.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, textureData)
87
88 return label_texture, width, height, w, h
The loadText object takes a string that it will render to a texture.
Optionally it takes a font size, a color, a font name, and an
antialias flag. Note that the color parameteris passed to
PyGame, and it expects values in the range 0-255 instead of 0-1.0 like
we use with OpenGL. Font is the filename for a TrueType font
file, if it is None, then the PyGame default font is used.
Another important thing to note is that the text string doesn't support newline characters, so it's one line at a time.
Lines 66 and 67 use the PyGame font library to render our text to an
image surface, then on lines 68 and 69 we get it's width and height.
Because we are using OpenGL, to use our image that has text on it, we
need it's size to be a power of two. So lines 70 to 75 find the
smallest power of two values that our image can fit inside.
Lines 77 to 80 are preparing a texture exactly the same way we did with
our image loader. Lines 82 and 83 are a bit different though.
Line 82 is creating an data string the with null values, that is
the power of two size we want for our new texture. We use this
string on line 83 to create a texture that is blank, and is large
enough to contain our image.
Line 85 takes our image and converts it to a string. Then on line 86 we copy the data into our new texture.
The function returns a texture id and dimensions, like the loadImage
function, but it also returns an extra width height pair. The
first pair is the pixel dimensions the text fills, the second pair is
the dimensions of the OpenGL texture.
So, now lets use the new function.
Example3a.py:
1 #!/usr/bin/python
2
3 import gutil
4 import pygame
5 from pygame.locals import *
6 from OpenGL.GL import *
7
8 from Image import Image
9
10
11 def main():
12 pygame.init()
13 gutil.initializeDisplay(800, 600)
14
15 done = False
16
17 cow = Image('cow')
18 alien = Image('alien')
19
20 white = (255,255,255,255)
21 stringTex, w, h, tw, th = gutil.loadText("Cow!", color=white)
22 stringDL = gutil.createTexDL(stringTex, tw, th)
23
24 while not done:
25 glClear(GL_COLOR_BUFFER_BIT)
26 glLoadIdentity()
27 glColor4f(1.0,1.0,1.0,1.0)
28 glTranslatef(100, 400, 0)
29 glCallList(stringDL)
30
31 cow.draw(pos=(100,100),width=128,height=128)
32 alien.draw(pos=(400, 400),rotation=-15,color=(.9,.3,.2,1))
33
34
35 pygame.display.flip()
36
37 eventlist = pygame.event.get()
38 for event in eventlist:
39 if event.type == QUIT \
40 or event.type == KEYDOWN and event.key == K_ESCAPE:
41 done = True
42
43 if __name__ == '__main__':
44 main()
This code follows quite closely from example 2a. Note that we
define our color the way PyGame expects on line 20. Line 21
generates a texture from the string "Cow!", then line 22 wraps it in a
display list for efficient rendering.
Line 25 is new. Here we are clearing the screen every frame.
In the past we didn't need to do this because we were drawing the
same image in the same place every frame. We still do this with
our font texture, but the difference is that now we have some pixels
that are semitransparent because of the font antialiasing. If we
weren't clearing the screen, we would be repeatedly drawing
semitransparent pixels over top of the same location. After a few
frames, these pixels would be solid white.
Lines 26 to 29 draw the string texture on the screen, in a manner very similar to how we drew images in example 2a.
Up to index
Back to Example 2b
On to Example 3b