[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] Re: BOUNCE pygame-users@seul.org: Non-member submission from ["David Keeney" <dkeeney@travelbyroad.net>]
Lì giovedì, 2004/06/24 alle 20:57, -0500, listbox@travelbyroad.net ha
> > I have borrowed some code from pyUI, changed it a little bit and made it
> > into a Font class that load any font available from pygame and render it
> > into a texture. it is just 100 lines but I don't know the policy of this
> > list about long emails containing code. just send? :)
>
> I would appreciate receiving the code, if you don't mind sharing it. I
> will add it to my sourceforge.net file release as well (at
> pduel.sourceforge.net).
as I said I wrote this code after looking at PyUI way of doing it. mine
is a little bit more flexible but the general idea is PyUI's. surely I
don't mind sharing something that is already shared and is mine only for
about 10%... here it goes:
class Font(object):
"""Render a whole font on a texture and use it to render text.
Heavily inspired by PyUI, distribute under the same license, please.
"""
def __init__(self, fontname=None, filename=None, size=10):
"""Pass to me a file name or a system font name."""
self.fontname = fontname
self.filename = filename
self.size = size
if self.filename:
self.font = pygame.font.Font(fontfile, size)
else:
self.font = pygame.font.SysFont(fontname, size)
self.metrics = []
self.create_texture()
def create_texture(self, lowchar=32, highchar=127):
"""Create a texture holding the whole font.
Note that only chars in the range [32,127], i.e., standard ASCII
are generated by default.
"""
self.lowchar = lowchar
surfaces = []
for i in range(lowchar, highchar+1):
try:
surf = self.font.render(chr(i), 1, (255,255,255,255))
except:
surfaces.append(None)
else:
surfaces.append(surf)
tw = reduce(lambda x, y: x + (y is not None and y.get_width() or 0),
surfaces, 0)
# FIXME: copied this from pyui, need to fix to calculate minimum
# dimensions to not waste texture memory
if tw > 1300:
tsize = 512
else:
tsize = 256
# this taken from pyui too but it also works with generic surface
# and plain convert(): need to investigate if we really gain speed
# this way
self.image = pygame.surface.Surface(
(tsize,tsize), HWSURFACE|SRCALPHA, 32).convert_alpha()
self.image.fill((0,0,0,0))
# create the texture image
x = y = c = h = 0
for surf in surfaces:
if surf is None:
self.metrics.append((0, 0, (0,0,0,0)))
continue
if x + surf.get_width() > tsize:
y += h
x = h = 0
self.image.blit(surf, (x,y))
l = float(x)/tsize
b = 1.0 - float(y)/tsize
r = float(x + surf.get_width()) / tsize
t = 1.0 - float(y + surf.get_height()) / tsize
self.metrics.append(
(surf.get_width(), surf.get_height(), (l,t,r,b)))
x += surf.get_width()
c += 1
h = max(h, surf.get_height())
# copy texture image to texture and create procedure lists
self.texture = glGenTextures(1)
data = pygame.image.tostring(self.image, "RGBA", 1)
glBindTexture(GL_TEXTURE_2D, self.texture)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tsize, tsize, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
self.procedures = []
for w, h, coords in self.metrics:
# remember: coords is (left,top,right,bottom)
if w == 0 and h == 0:
self.procedures.append(0)
continue
# TODO: we probably can generale all the lists by calling
# glGenLists once
l = glGenLists(1)
glNewList(l, GL_COMPILE)
# we don't bind the texture because the draw routine will do
# that only once to speed-up long strings rendering
glBegin(GL_QUADS)
glTexCoord2f(coords[0], coords[1]) ; glVertex2i(0, 0)
glTexCoord2f(coords[0], coords[3]) ; glVertex2i(0, h)
glTexCoord2f(coords[2], coords[3]) ; glVertex2i(w, h)
glTexCoord2f(coords[2], coords[1]) ; glVertex2i(w, 0)
glEnd()
glEndList()
self.procedures.append(l)
def draw_text(self, text, pos=(0,0), color=(255,255,255,255)):
"""Draw the given text.
Note that we pass color as unsigned bytes, we are in 2D after all.
"""
glBindTexture(GL_TEXTURE_2D, self.texture)
# TODO: pass blend function as a parameter? usually text overlays
# don't have alpha but we use GL_SRC_ALPHA anyway because i like it.
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4ub(*color)
glPushMatrix()
glTranslatef(pos[0], pos[1], 0)
for c in text:
w = self.metrics[ord(c)-self.lowchar][0]
glCallList(self.procedures[ord(c)-self.lowchar])
glTranslatef(w, 0, 0)
glPopMatrix()
def test(self):
"""Draw the whole texture on a 1x1 quad, as a test.
Orthographic projection should be already setup to use 'screen
coordinates' in the GL window.
"""
size = self.image.get_width()
glBindTexture(GL_TEXTURE_2D, self.texture)
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(1.0,1.0,1.0,1.0)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex3f( 0.0, 0.0, 0.0)
glTexCoord2f(1.0, 0.0); glVertex3f(size, 0.0, 0.0)
glTexCoord2f(1.0, 1.0); glVertex3f(size, size, 0.0)
glTexCoord2f(0.0, 1.0); glVertex3f( 0.0, size, 0.0)
glEnd()
hope this helps,
federico
--
Federico Di Gregorio http://people.initd.org/fog
Debian GNU/Linux Developer fog@debian.org
INIT.D Developer fog@initd.org
All'inizio ho scritto un programma proprietario, in esclusiva per il
cliente; è stato tristissimo, perché mi ha succhiato un pezzo di
anima. -- Alessandro Rubini