I'm writting a simple bitmap font renderer in pySFML and wanted to ask is there a better and faster way to approach this problem. Don't really know if my approach is optimal.
I'm using VertexArray (
http://www.python-sfml.org/api/graphics.html#id22) and create a quad for each character in a string. Each quad has appropriate texture coordinates applied.
Example font (PNG file):
Font rendering code:
import sfml
class BitmapFont(object):
'''
Loads a bitmap font.
`chars` is string with all characters available in the font file, example: '+0123456789x'.
`widths` is mapping between characters and character width in pixels.
'''
def __init__(self, path, chars, widths, colors=1, kerning=0):
self.texture = sfml.Texture.from_file(path)
self.colors = colors
self.height = self.texture.height / self.colors
self.chars = chars
self.kerning = kerning
self.widths = widths
self.glyphs = []
y = 0
for color in range(self.colors):
x = 0
self.glyphs.append({})
for char in self.chars:
glyph_pos = x, y
glyph_size = self.widths[char], self.height
glyph = sfml.Rectangle(glyph_pos, glyph_size)
self.glyphs[color][char] = glyph
x += glyph.width
y += self.height
class BitmapText(sfml.TransformableDrawable):
'''Used to render text with `BitmapFonts`.'''
def __init__(self, string='', font=None, color=0, align='left', position=(0, 0)):
super().__init__()
self.vertices = sfml.VertexArray(sfml.PrimitiveType.QUADS, 4)
self.font = font
self.color = color
self._string = ''
self.string = string
self.position = position
@property
def string(self):
return self._string
@string.setter
def string(self, value):
'''Calculates new vertices each time string has changed.'''
# This function is slowest and probably can be optimized.
if value == self._string:
return
if len(value) != len(self._string):
self.vertices.resize(4 * len(value))
self._string = value
x = 0
y = 0
vertices = self.vertices
glyphs = self.font.glyphs[self.color]
for i, char in enumerate(self._string):
glyph = glyphs[char]
p = i * 4
vertices[p + 0].position = x, y
vertices[p + 1].position = x + glyph.width, y
vertices[p + 2].position = x + glyph.width, y + glyph.height
vertices[p + 3].position = x, y + glyph.height
vertices[p + 0].tex_coords = glyph.left, glyph.top
vertices[p + 1].tex_coords = glyph.right, glyph.top
vertices[p + 2].tex_coords = glyph.right, glyph.bottom
vertices[p + 3].tex_coords = glyph.left, glyph.bottom
x += glyph.width + self.font.kerning
def draw(self, target, states):
'''Draws whole string using texture from a font.'''
states.texture = self.font.texture
states.transform = self.transform
target.draw(self.vertices, states)
Simple example usage with benchmark (FPS counter) is attached.
I'm using Python 3.3, pySFML 1.3, SFML 2.0 and Windows.
Note, that I've asked same question on StackOverflow, but nobody replied, so I've decided here would be a better place to ask.