2013-11-01 31 views
0

我在pySFML中写了一个简单的位图字体渲染器,想问问有没有更好更快的方法来解决这个问题。SFML中的位图字体(OpenGL)

我使用VertexArray并为字符串中的每个字符创建一个四元组。每个四边形具有适当的纹理坐标。

实施例的字体(PNG文件):Bitmap font example

字体呈现代码:

import sfml 


class BitmapFont(object): 
    ''' 
    Loads a bitmap font. 
    `chars` is string with all characters available in the font file, example: 'x'. 
    `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) 

简单的基准与FPS计数器:

from random import random, randint 

import sfml 

from font import BitmapFont, BitmapText 


font = sfml.Font.from_file('arial.ttf') 

bitmap_font = BitmapFont('font.png', chars='-x', kerning=-3, 
         widths={'x': 21, '+': 18, '0': 18, '1': 14, '2': 18, '3': 18, '4': 19, '5': 18, '6': 18, 
           '7': 17, '8': 18, '9': 18, '-': 17, ' ': 8}) 

window = sfml.RenderWindow(sfml.VideoMode(960, 640), 'Font test') 

fps_text = sfml.Text('', font, 18) 
fps_text.position = 10, 10 
fps_text.color = sfml.Color.WHITE 

fps_text_shadow = sfml.Text('', font, 18) 
fps_text_shadow.position = 12, 12 
fps_text_shadow.color = sfml.Color.BLACK 

frame = fps = frame_time = 0 

clock = sfml.Clock() 
texts = [BitmapText('x', font=bitmap_font, color=randint(0, bitmap_font.colors - 1)) for i in range(1000)] 

while window.is_open: 
    for event in window.events: 
     if type(event) is sfml.CloseEvent: 
      window.close() 

    time_delta = clock.restart().seconds 
    if time_delta > .2: 
     continue 

    frame_time += time_delta 
    if frame_time >= 1: 
     fps = frame 
     frame_time = frame = 0 
     fps_text_shadow.string = fps_text.string = 'FPS: {fps}'.format(fps=fps) 
    else: 
     frame += 1 

    window.clear(sfml.Color(63, 63, 63)) 

    for t in texts: 
     t.position = random() * 960, random() * 640 
     t.string = str(randint(0, 10000000)) 
     window.draw(t) 

    window.draw(fps_text_shadow) 
    window.draw(fps_text) 
    window.display() 

我使用Python 3.3,pySFML 1.3, SFML 2.0和Windows。

回答

0

Laurent Gomila(SFML的作者)在other forum中证实,我对位图字体的方法与SFML中的矢量字体实现相同(即VertexArray和每个字符的四边形)。