Index: fretsonfire-1.2.451.dfsg/src/Font.py =================================================================== --- FretsOnFire-src-1.2.512/src/Font.py 2007-09-04 19:39:22.000000000 +0100 +++ FretsOnFire-src-1.2.451/src/Font.py 2007-02-20 19:42:45.000000000 +0000 @@ -21,26 +21,22 @@ ##################################################################### import pygame -import numpy from OpenGL.GL import * import sys -from Texture import Texture, TextureAtlas, TextureAtlasFullException +from Texture import Texture class Font: """A texture-mapped font.""" def __init__(self, fileName, size, bold = False, italic = False, underline = False, outline = True, scale = 1.0, reversed = False, systemFont = False): pygame.font.init() - self.size = size - self.scale = scale - self.glyphCache = {} - self.glyphSizeCache = {} - self.outline = outline - self.glyphTextures = [] - self.reversed = reversed - self.stringCache = {} - self.stringCacheLimit = 256 + self.size = size + self.scale = scale + self.glyphCache = {} + self.glyphSizeCache = {} + self.outline = outline + self.reversed = reversed # Try loading a system font first if one was requested self.font = None if systemFont and sys.platform != "win32": @@ -91,71 +87,11 @@ """ texture.setFilter(GL_LINEAR, GL_LINEAR) texture.setRepeat(GL_CLAMP, GL_CLAMP) - self.glyphCache[character] = (texture, (0.0, 0.0, texture.size[0], texture.size[1])) + self.glyphCache[character] = texture s = .75 * self.getHeight() / float(texture.pixelSize[0]) self.glyphSizeCache[character] = (texture.pixelSize[0] * s, texture.pixelSize[1] * s) - def _renderString(self, text, pos, direction, scale): - if not text: - return - - if not (text, scale) in self.stringCache: - currentTexture = None - #x, y = pos[0], pos[1] - x, y = 0.0, 0.0 - vertices = numpy.empty((4 * len(text), 2), numpy.float32) - texCoords = numpy.empty((4 * len(text), 2), numpy.float32) - vertexCount = 0 - cacheEntry = [] - - for i, ch in enumerate(text): - g, coordinates = self.getGlyph(ch) - w, h = self.getStringSize(ch, scale = scale) - tx1, ty1, tx2, ty2 = coordinates - - # Set the initial texture - if currentTexture is None: - currentTexture = g - - # If the texture changed, flush the geometry - if currentTexture != g: - cacheEntry.append((currentTexture, vertexCount, numpy.array(vertices[:vertexCount]), numpy.array(texCoords[:vertexCount]))) - currentTexture = g - vertexCount = 0 - - vertices[vertexCount + 0] = (x, y) - vertices[vertexCount + 1] = (x + w, y) - vertices[vertexCount + 2] = (x + w, y + h) - vertices[vertexCount + 3] = (x, y + h) - texCoords[vertexCount + 0] = (tx1, ty2) - texCoords[vertexCount + 1] = (tx2, ty2) - texCoords[vertexCount + 2] = (tx2, ty1) - texCoords[vertexCount + 3] = (tx1, ty1) - vertexCount += 4 - - x += w * direction[0] - y += w * direction[1] - cacheEntry.append((currentTexture, vertexCount, vertices[:vertexCount], texCoords[:vertexCount])) - - # Don't store very short strings - if len(text) > 5: - # Limit the cache size - if len(self.stringCache) > self.stringCacheLimit: - del self.stringCache[self.stringCache.keys()[0]] - self.stringCache[(text, scale)] = cacheEntry - else: - cacheEntry = self.stringCache[(text, scale)] - - glPushMatrix() - glTranslatef(pos[0], pos[1], 0) - for texture, vertexCount, vertices, texCoords in cacheEntry: - texture.bind() - glVertexPointer(2, GL_FLOAT, 0, vertices) - glTexCoordPointer(2, GL_FLOAT, 0, texCoords) - glDrawArrays(GL_QUADS, 0, vertexCount) - glPopMatrix() - - def render(self, text, pos = (0, 0), direction = (1, 0), scale = 0.002): + def render(self, text, pos = (0, 0), direction = (1, 0, 0), scale = 0.002): """ Draw some text. @@ -169,43 +105,75 @@ glEnableClientState(GL_TEXTURE_COORD_ARRAY) scale *= self.scale - + glPushMatrix() + glTranslatef(pos[0], pos[1], 0) + if self.reversed: text = "".join(reversed(text)) if self.outline: glPushAttrib(GL_CURRENT_BIT) - glColor4f(0, 0, 0, glGetFloatv(GL_CURRENT_COLOR)[3]) - self._renderString(text, (pos[0] + 0.003, pos[1] + 0.003), direction, scale) + glPushMatrix() + glColor4f(0, 0, 0, .25 * glGetDoublev(GL_CURRENT_COLOR)[3]) + for ch in text: + g = self.getGlyph(ch) + w, h = self.getStringSize(ch, scale = scale) + tw, th = g.size + + glVertexPointerf([(0.0, 0.0, 0.0), (w, 0.0, 0.0), (0.0, h, 0.0), (w, h, 0.0)]) + glTexCoordPointerf([(0.0, th), (tw, th), (0.0, 0.0), (tw, 0.0)]) + + g.bind() + + blur = 2 * 0.002 + for offset in [(-.7, -.7), (0, -1), (.7, -.7), (-1, 0), (1, 0), (-.7, .7), (0, 1), (.7, .7)]: + glPushMatrix() + glTranslatef( blur * offset[0], blur * offset[1], 0) + glDrawElementsui(GL_TRIANGLE_STRIP, [0, 1, 2, 3]) + glPopMatrix() + + glTranslatef(w * direction[0], + w * direction[1], + w * direction[2]) + glPopAttrib() + glPopMatrix() + + for ch in text: + g = self.getGlyph(ch) + w, h = self.getStringSize(ch, scale = scale) + tw, th = g.size + + glVertexPointerf([(0.0, 0.0, 0.0), (w, 0.0, 0.0), (0.0, h, 0.0), (w, h, 0.0)]) + glTexCoordPointerf([(0.0, th), (tw, th), (0.0, 0.0), (tw, 0.0)]) + + g.bind() + glDrawElementsui(GL_TRIANGLE_STRIP, [0, 1, 2, 3]) + + glTranslatef(w * direction[0], + w * direction[1], + w * direction[2]) + + glPopMatrix() - self._renderString(text, pos, direction, scale) - glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_TEXTURE_COORD_ARRAY) glDisable(GL_TEXTURE_2D) - def _allocateGlyphTexture(self): - t = TextureAtlas(size = glGetInteger(GL_MAX_TEXTURE_SIZE)) - t.texture.setFilter(GL_LINEAR, GL_LINEAR) - t.texture.setRepeat(GL_CLAMP, GL_CLAMP) - self.glyphTextures.append(t) - return t - def getGlyph(self, ch): """ - Get a (L{Texture}, coordinate tuple) pair for a given character. + Get the L{Texture} for a given character. @param ch: Character - @return: (L{Texture} instance, coordinate tuple) + @return: L{Texture} instance """ try: return self.glyphCache[ch] except KeyError: s = self.font.render(ch, True, (255, 255, 255)) - # Draw outlines """ + # Draw outlines import Image, ImageFilter srcImg = Image.fromstring("RGBA", s.get_size(), pygame.image.tostring(s, "RGBA")) img = Image.fromstring("RGBA", s.get_size(), pygame.image.tostring(s, "RGBA")) @@ -222,19 +190,11 @@ img.putpixel((x, y), (0, 0, 0, a / n)) s = pygame.image.fromstring(img.tostring(), s.get_size(), "RGBA") """ - - if not self.glyphTextures: - texture = self._allocateGlyphTexture() - else: - texture = self.glyphTextures[-1] - - # Insert the texture into the glyph cache - try: - coordinates = texture.add(s) - except TextureAtlasFullException: - # Try again with a fresh atlas - texture = self._allocateGlyphTexture() - return self.getGlyph(ch) - - self.glyphCache[ch] = (texture, coordinates) - return (texture, coordinates) + + t = Texture() + t.setFilter(GL_LINEAR, GL_LINEAR) + t.setRepeat(GL_CLAMP, GL_CLAMP) + t.loadSurface(s, alphaChannel = True) + del s + self.glyphCache[ch] = t + return t