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  */
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 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color,...
Definition: pnmImage.cxx:48
A single glyph in a PNMTextMaker.
Definition: pnmTextGlyph.h:25
int get_advance() const
Returns the number of pixels by which the pen should be advanced after rendering this glyph.
Definition: pnmTextGlyph.I:19
void place(PNMImage &dest_image, int xp, int yp, const LColor &fg)
Copies the glyph to the indicated destination image at the indicated origin.
This object uses the Freetype library to generate text directly into an image.
Definition: pnmTextMaker.h:35
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,...
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
PNMTextGlyph * get_glyph(int character)
Returns the glyph for the indicated index, or NULL if it is not defined in the font.
int calc_width(const std::string &text)
Returns the width in pixels of the indicated line of text.
Definition: pnmTextMaker.I:135
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.