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