Class: Tea::Font

Inherits:
Object
  • Object
show all
Defined in:
lib/tea/c_font.rb

Overview

Fonts are used to draw text. They do this by mapping characters to images that are loaded when the Font is created.

Tea supports bitmap fonts, and Karl Bartel’s SFont format.

Bitmap fonts (Tea::Font::BITMAP_FONT) are a single row of 256 characters in a BMP or PNG image. If the image has intrinsic transparency, it will be used by default. Otherwise, loading the font with the color transparency option will consider one color as the ‘transparent color’ and no such pixels will be drawn.

SFont fonts (Tea::Font::SFONT) are also a single row of character images, but ranging from ASCII 33 to ASCII 127:

! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ `
a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~

SFont uses variable width characters. Characters are separated by magenta (255, 0, 255) in the top pixel row, so the pixels directly under the magenta strips would be the gaps between characters, e.g.:

____       ____       ____       ____   <-- magenta strips
....   #   .... ####  ....  ###  ....
....  # #  .... #   # .... #   # ....
.... ##### .... ####  .... #     ....   <-- gaps between characters
.... #   # .... #   # .... #   # ....       (can be any color)
.... #   # .... ####  ....  ###  ....

The width of a space is not defined in the SFont format, so Tea uses the width of the first character, ‘!’.

Defined Under Namespace

Classes: WrappedLines

Constant Summary collapse

BITMAP_FONT =

font_type constant for bitmap fonts.

:BITMAP_FONT
SFONT =
:SFONT
BITMAP_FONT_START =
0
BITMAP_FONT_LENGTH =
256
SFONT_START =
33
SFONT_LENGTH =
94
CODE_POINT_SPACE =
32

Instance Method Summary collapse

Constructor Details

#initialize(path, font_type, options = nil) ⇒ Font

Create a new font from a font file given by path.

font_type is one of Tea::Font::BITMAP_FONT or Tea::Font::SFONT. See Tea::Font for font format details.

Optional hash arguments:

+:transparent_color+::  If +font_type+ is Tea::Font::BITMAP_FONT, this
                        is the color that should not be drawn when
                        rendering text.  Default: Tea::Color::MAGENTA.

May raise Tea::Error on failure.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/tea/c_font.rb', line 68

def initialize(path, font_type, options=nil)
  font = SDL::Surface.load(path)
  transparent_color = options ? options[:transparent_color] : nil
  @font_type = font_type

  case font_type
  when BITMAP_FONT
    @glyphs = letters_from_bitmap_font(font, transparent_color)
  when SFONT
    @glyphs = letters_from_sfont(font, transparent_color)
  end
rescue SDL::Error => e
  raise Tea::Error, e.message, e.backtrace
end

Instance Method Details

#draw_to(bitmap, x, y, string) ⇒ Object

Write the given string onto the bitmap at (x, y).



184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/tea/c_font.rb', line 184

def draw_to(bitmap, x, y, string)
  draw_x = x
  each_code_point(string) do |pt|
    glyph = get_glyph(pt)
    if glyph
      bitmap.blit glyph, draw_x, y
      draw_x += glyph.w
    else
      draw_x += get_glyph_w(pt)
    end
  end

  string
end

#hObject

Get the height of the font’s characters.



91
92
93
94
# File 'lib/tea/c_font.rb', line 91

def h
  # Nothing special about 0, all chars are the same height.
  @glyphs[0].h
end

#string_w(string) ⇒ Object

Calculate the pixel width of a string rendered with this font.



84
85
86
87
88
# File 'lib/tea/c_font.rb', line 84

def string_w(string)
  w = 0
  each_code_point(string) { |pt| w += get_glyph_w(pt) }
  w
end

#word_wrap(string, width, initial_left_margin = 0) ⇒ Object

Split a string into an array of lines such that each line, when rendered using this font, is no wider than width.

initial_left_margin sets the starting position for the first line of wrapping.

Returns an array of strings, representing the split lines.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/tea/c_font.rb', line 109

def word_wrap(string, width, initial_left_margin=0)
  # This is adapted from the Sphere RPG Engine's font word wrapping code.
  # Rickety, but battle-tested.
  space_w = string_w(" ")
  tab = " " * 4
  tab_w = string_w(tab)

  x = initial_left_margin

  lines = WrappedLines.new
  lines.push ""
  word = ""
  word_w = 0

  # No good string character iterators for Ruby 1.8, hence crappy O(n) access.
  string.length.times do |i|
    # Crappy O(n) access here.
    char = string[i, 1]

    case char
    when " ", "\t"
      if char == " "
        spacing = " "
        spacing_w = space_w
      elsif char == "\t"
        spacing = tab
        spacing_w = tab_w
      end

      if x + word_w + spacing_w > width
        lines.push word + spacing
        x = word_w + spacing_w
      else
        lines[-1] += word + spacing
        x += word_w + spacing_w
      end

      word = ""
      word_w = 0

    when "\n"
      lines[-1] += word
      lines.push ""
      x = 0
      word = ""
      word_w = 0

    else
      char_w = string_w(char)

      if word_w + char_w > width && x == 0
        # Word is too long for a single line, so split it.
        lines[-1] += word
        lines.push ""
        word = ""
        word_w = 0
      elsif x + word_w + char_w > width
        # Start a new line.
        x = 0
        lines.push ""
      end

      word += char
      word_w += char_w

    end
  end

  lines[-1] += word
  lines.end_x = x + word_w

  lines
end