Panda3D
pnmTextMaker.cxx
1 // Filename: textMaker.cxx
2 // Created by: drose (03Apr02)
3 //
4 //////////////////////////////////////////////////////////////////////
5 // PANDA 3D SOFTWARE
6 // Copyright (c) Carnegie Mellon University. All rights reserved.
7 //
8 // All use of this software is subject to the terms of the revised BSD
9 // license. You should have received a copy of this license along
10 // with this source code in a file named "LICENSE."
11 //
12 ////////////////////////////////////////////////////////////////////
13 
14 #include "pnmTextMaker.h"
15 #include "pnmTextGlyph.h"
16 #include "filename.h"
17 #include "pnmImage.h"
18 
19 ////////////////////////////////////////////////////////////////////
20 // Function: PNMTextMaker::Constructor
21 // Access: Public
22 // Description: The constructor expects the name of some font file
23 // that FreeType can read, along with face_index,
24 // indicating which font within the file to load
25 // (usually 0).
26 ////////////////////////////////////////////////////////////////////
28 PNMTextMaker(const Filename &font_filename, int face_index) {
29  initialize();
30  _is_valid = load_font(font_filename, face_index);
31 }
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: PNMTextMaker::Constructor
35 // Access: Public
36 // Description: This constructor works as above, but it takes the
37 // font data from an in-memory buffer instead of from a
38 // named file.
39 ////////////////////////////////////////////////////////////////////
41 PNMTextMaker(const char *font_data, int data_length, int face_index) {
42  initialize();
43  _is_valid = load_font(font_data, data_length, face_index);
44 }
45 
46 ////////////////////////////////////////////////////////////////////
47 // Function: PNMTextMaker::Copy Constructor
48 // Access: Public
49 // Description:
50 ////////////////////////////////////////////////////////////////////
52 PNMTextMaker(const PNMTextMaker &copy) :
53  FreetypeFont(copy),
54  _is_valid(copy._is_valid),
55  _align(copy._align),
56  _interior_flag(copy._interior_flag),
57  _fg(copy._fg),
58  _interior(copy._interior)
59 {
60 }
61 
62 ////////////////////////////////////////////////////////////////////
63 // Function: PNMTextMaker::Copy Constructor
64 // Access: Public
65 // Description:
66 ////////////////////////////////////////////////////////////////////
68 PNMTextMaker(const FreetypeFont &copy) :
69  FreetypeFont(copy),
70  _is_valid(true)
71 {
72  initialize();
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: PNMTextMaker::Destructor
77 // Access: Public
78 // Description:
79 ////////////////////////////////////////////////////////////////////
80 PNMTextMaker::
81 ~PNMTextMaker() {
82  empty_cache();
83 }
84 
85 ////////////////////////////////////////////////////////////////////
86 // Function: PNMTextMaker::generate_into
87 // Access: Public
88 // Description: Generates a single line of text into the indicated
89 // image at the indicated position; the return value is
90 // the total width in pixels.
91 ////////////////////////////////////////////////////////////////////
93 generate_into(const wstring &text, PNMImage &dest_image, int x, int y) {
94  // First, measure the total width in pixels.
95  int width = calc_width(text);
96 
97  int xp = x;
98  int yp = y;
99 
100  switch (_align) {
101  case A_left:
102  xp = x;
103  break;
104 
105  case A_center:
106  xp = x - (width / 2);
107  break;
108 
109  case A_right:
110  xp = x - width;
111  break;
112  }
113 
114  // Now place the text.
115  wstring::const_iterator ti;
116  for (ti = text.begin(); ti != text.end(); ++ti) {
117  int ch = (*ti);
118  PNMTextGlyph *glyph = get_glyph(ch);
119  if (_interior_flag) {
120  glyph->place(dest_image, xp, yp, _fg, _interior);
121  } else {
122  glyph->place(dest_image, xp, yp, _fg);
123  }
124  xp += glyph->get_advance();
125  }
126 
127  return width;
128 }
129 
130 ////////////////////////////////////////////////////////////////////
131 // Function: PNMTextMaker::calc_width
132 // Access: Public
133 // Description: Returns the width in pixels of the indicated line of
134 // text.
135 ////////////////////////////////////////////////////////////////////
136 int PNMTextMaker::
137 calc_width(const wstring &text) {
138  int width = 0;
139  wstring::const_iterator ti;
140  for (ti = text.begin(); ti != text.end(); ++ti) {
141  int ch = (*ti);
142  PNMTextGlyph *glyph = get_glyph(ch);
143  width += glyph->get_advance();
144  }
145  return width;
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: PNMTextMaker::get_glyph
150 // Access: Public
151 // Description: Returns the glyph for the indicated index, or NULL if
152 // it is not defined in the font.
153 ////////////////////////////////////////////////////////////////////
155 get_glyph(int character) {
156  FT_Face face = acquire_face();
157  int glyph_index = FT_Get_Char_Index(face, character);
158  release_face(face);
159 
160  Glyphs::iterator gi;
161  gi = _glyphs.find(glyph_index);
162  if (gi != _glyphs.end()) {
163  return (*gi).second;
164  }
165 
166  PNMTextGlyph *glyph = make_glyph(glyph_index);
167  _glyphs.insert(Glyphs::value_type(glyph_index, glyph));
168  return glyph;
169 }
170 
171 ////////////////////////////////////////////////////////////////////
172 // Function: PNMTextMaker::initialize
173 // Access: Private
174 // Description: Called from both constructors to set up some initial
175 // values.
176 ////////////////////////////////////////////////////////////////////
177 void PNMTextMaker::
178 initialize() {
179  _align = A_left;
180  _interior_flag = false;
181  _fg.set(0.0f, 0.0f, 0.0f, 1.0f);
182  _interior.set(0.5f, 0.5f, 0.5f, 1.0f);
183 }
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: PNMTextMaker::make_glyph
187 // Access: Private
188 // Description: Creates a new PNMTextGlyph object for the indicated
189 // index, if possible.
190 ////////////////////////////////////////////////////////////////////
191 PNMTextGlyph *PNMTextMaker::
192 make_glyph(int glyph_index) {
193  FT_Face face = acquire_face();
194  if (!load_glyph(face, glyph_index)) {
195  release_face(face);
196  return (PNMTextGlyph *)NULL;
197  }
198 
199  FT_GlyphSlot slot = face->glyph;
200 
201  FT_Bitmap &bitmap = slot->bitmap;
202 
203  double advance = slot->advance.x / 64.0;
204 
205  PNMTextGlyph *glyph = new PNMTextGlyph(advance);
206 
207  if (bitmap.width == 0 || bitmap.rows == 0) {
208  // If we got an empty bitmap, it's a special case.
209  glyph->rescale(_scale_factor);
210 
211  } else {
212  PNMImage &glyph_image = glyph->_image;
213  glyph_image.clear(bitmap.width, bitmap.rows, 3);
214  copy_bitmap_to_pnmimage(bitmap, glyph_image);
215 
216  glyph->_top = slot->bitmap_top;
217  glyph->_left = slot->bitmap_left;
218 
219  if (_interior_flag) {
220  glyph->determine_interior();
221  }
222  glyph->rescale(_scale_factor);
223  }
224 
225  release_face(face);
226  return glyph;
227 }
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: PNMTextMaker::empty_cache
231 // Access: Private
232 // Description: Empties the cache of previously-generated glyphs.
233 ////////////////////////////////////////////////////////////////////
234 void PNMTextMaker::
235 empty_cache() {
236  Glyphs::iterator gi;
237  for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
238  PNMTextGlyph *glyph = (*gi).second;
239  delete glyph;
240  }
241 }
int get_advance() const
Returns the number of pixels by which the pen should be advanced after rendering this glyph...
Definition: pnmTextGlyph.I:23
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:68
int calc_width(const string &text)
Returns the width in pixels of the indicated line of text.
Definition: pnmTextMaker.I:148
PNMTextMaker(const Filename &font_filename, int face_index)
The constructor expects the name of some font file that FreeType can read, along with face_index...
This object uses the Freetype library to generate text directly into an image.
Definition: pnmTextMaker.h:39
int generate_into(const string &text, PNMImage &dest_image, int x, int y)
Generates a single line of text into the indicated image at the indicated position; the return value ...
Definition: pnmTextMaker.I:135
void place(PNMImage &dest_image, int xp, int yp, const LColor &fg)
Copies the glyph to the indicated destination image at the indicated origin.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color, type, etc).
Definition: pnmImage.cxx:50
A single glyph in a PNMTextMaker.
Definition: pnmTextGlyph.h:27
PNMTextGlyph * get_glyph(int character)
Returns the glyph for the indicated index, or NULL if it is not defined in the font.