Panda3D
Loading...
Searching...
No Matches
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
21using 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 */
29PNMTextMaker(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 */
39PNMTextMaker(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 */
48PNMTextMaker(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 */
63PNMTextMaker(const FreetypeFont &copy) :
64 FreetypeFont(copy),
65 _is_valid(true)
66{
67 initialize();
68}
69
70/**
71 *
72 */
73PNMTextMaker::
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 */
83generate_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 */
124calc_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 */
140get_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 */
159void PNMTextMaker::
160initialize() {
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 */
171PNMTextGlyph *PNMTextMaker::
172make_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 */
257void PNMTextMaker::
258empty_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:44
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.
int get_advance() const
Returns the number of pixels by which the pen should be advanced after rendering this glyph.
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.
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 ...
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.
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.