Panda3D

eggMakeFont.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 eggMakeFont.cxx
10 * @author drose
11 * @date 2001-02-16
12 */
13
14 #include "eggMakeFont.h"
15 #include "rangeIterator.h"
16 #include "palettizer.h"
17 #include "filenameUnifier.h"
18 #include "eggFile.h"
19 #include "textureImage.h"
20 #include "sourceTextureImage.h"
21 #include "pnmTextMaker.h"
22 #include "pnmTextGlyph.h"
23 #include "eggData.h"
24 #include "eggGroup.h"
25 #include "eggPoint.h"
26 #include "eggPolygon.h"
27 #include "eggTexture.h"
28 #include "eggVertexPool.h"
29 #include "eggVertex.h"
30 #include "string_utils.h"
31 #include "dcast.h"
32
33 #include <ctype.h>
34
35 using std::string;
36
37 /**
38 *
39 */
40 EggMakeFont::
41 EggMakeFont() : EggWriter(true, false) {
42 set_program_brief("generates .egg files with rasterized font glyphs");
43 set_program_description
44 ("egg-mkfont uses the FreeType library to generate an egg file "
45 "and a series of texture images from a font file "
46 "input, such as a TTF file. The resulting egg file "
47 "can be loaded in Panda as a font for rendering text, even "
48 "if FreeType is not compiled into the executing Panda.\n\n"
49
50 "egg-mkfont will normally run the generated egg file through "
51 "egg-palettize automatically as part of the generation process. "
52 "This collects the individual glyph textures into a small number "
53 "of texture maps. If you intend to run the font through egg-palettize "
54 "yourself later, you may choose to omit this step.");
55
56 clear_runlines();
57 add_runline("[opts] -o output.egg font");
58 add_runline("[opts] font output.egg");
59
60 add_option
61 ("fg", "r,g,b[,a]", 0,
62 "Specifies the foreground color of the generated texture map. The "
63 "default is white: 1,1,1,1, which leads to the most flexibility "
64 "as the color can be modulated at runtime to any suitable color.",
65 &EggMakeFont::dispatch_color, nullptr, &_fg[0]);
66
67 add_option
68 ("bg", "r,g,b[,a]", 0,
69 "Specifies the background color of the generated texture map. The "
70 "default is transparent: 1,1,1,0, which allows the text to be "
71 "visible against any color background by placing a polygon of a "
72 "suitable color behind it. If the alpha component of either -fg "
73 "or -bg is not 1, the generated texture images will include an "
74 "alpha component; if both colors specify an alpha component of 1 "
75 "(or do not specify an alpha compenent), then the generated images "
76 "will not include an alpha component.",
77 &EggMakeFont::dispatch_color, nullptr, &_bg[0]);
78
79 add_option
80 ("interior", "r,g,b[,a]", 0,
81 "Specifies the color to render the interior part of a hollow font. "
82 "This is a special effect that involves analysis of the bitmap after "
83 "the font has been rendered, and so is more effective when the pixel "
84 "size is large. It also implies -noaa (but you can use a scale "
85 "factor with -sf to achieve antialiasing).",
86 &EggMakeFont::dispatch_color, &_got_interior, &_interior[0]);
87
88 add_option
89 ("chars", "range", 0,
90 "Specifies the characters of the font that are used. The range "
91 "specification may include combinations of decimal or hex unicode "
92 "values (where hex values are identified with a leading 0x), separated "
93 "by commas and hyphens to indicate ranges, e.g. '32-126,0xfa0-0xfff'. "
94 "It also may specify ranges of ASCII characters by enclosing them "
95 "within square brackets, e.g. '[A-Za-z0-9]'. If this is not specified, "
96 "the default set has all ASCII characters and an assorted set of "
97 "latin-1 characters, diacritics and punctuation marks.",
98 &EggMakeFont::dispatch_range, nullptr, &_range);
99
100 add_option
101 ("extra", "file.egg", 0,
102 "Specifies additional externally-painted glyphs to mix into the "
103 "generated egg file. The named egg file is expected to contain one "
104 "or more groups, each of which is named with the decimal unicode "
105 "number of a character and should contain one polygon. These groups "
106 "are simply copied into the output egg file as if they were generated "
107 "locally. This option may be repeated.",
108 &EggMakeFont::dispatch_vector_string, nullptr, &_extra_filenames);
109
110 add_option
111 ("ppu", "pixels", 0,
112 "Specify the pixels per unit. This is the number of pixels in the "
113 "generated texture map that are used for each onscreen unit (or each "
114 "10 points of font; see -ps). Setting this number larger results in "
115 "an easier-to-read font, but at the cost of more texture memory. "
116 "The default is 40.",
117 &EggMakeFont::dispatch_double, nullptr, &_pixels_per_unit);
118
119 add_option
120 ("ps", "size", 0,
121 "Specify the point size of the resulting font. This controls the "
122 "apparent size of the font when it is rendered onscreen. By convention, "
123 "a 10 point font is 1 screen unit high, so the default is 10.",
124 &EggMakeFont::dispatch_double, nullptr, &_point_size);
125
126 add_option
127 ("sdf", "", 0,
128 "If this is set, a signed distance field will be generated, which "
129 "results in crisp text even when the text is enlarged or zoomed in.",
130 &EggMakeFont::dispatch_true, nullptr, &_generate_distance_field);
131
132 add_option
133 ("pm", "n", 0,
134 "The number of extra pixels around a single character in the "
135 "generated polygon. This may be a floating-point number. The "
136 "default is 1.",
137 &EggMakeFont::dispatch_double, nullptr, &_poly_margin);
138
139 add_option
140 ("tm", "n", 0,
141 "The number of extra pixels around each character in the texture map. "
142 "This may only be an integer. The default is 2. This is meaningful "
143 "when -nopal is also used; in the normal case, use -pm to control "
144 "both the polygon size and the texture map spacing.",
145 &EggMakeFont::dispatch_int, nullptr, &_tex_margin);
146
147 add_option
148 ("rm", "n", 0,
149 "The amount of padding in screen units to place around the glyph when "
150 "rendered. This differs from -pm in that it has no effect on the "
151 "generated texture map, only on the generated egg. Use this in order to "
152 "space the characters out in case they appear to be too close together "
153 "when rendered. The default is 0.",
154 &EggMakeFont::dispatch_double, nullptr, &_render_margin);
155
156 add_option
157 ("sf", "factor", 0,
158 "The scale factor of the generated image. This is the factor by which "
159 "the font image is generated oversized, then reduced to its final size, "
160 "to improve antialiasing. If the specified font contains one "
161 "or more fixed-size fonts instead of a scalable font, the scale factor "
162 "may be automatically adjusted as necessary to scale the closest-"
163 "matching font to the desired pixel size. The default is 2.",
164 &EggMakeFont::dispatch_double, &_got_scale_factor, &_scale_factor);
165
166 add_option
167 ("noaa", "", 0,
168 "Disable low-level antialiasing by the Freetype library. "
169 "This is unrelated to the antialiasing that is applied due to the "
170 "scale factor specified by -sf; you may have either one, neither, or "
171 "both kinds of antialiasing enabled.",
172 &EggMakeFont::dispatch_none, &_no_native_aa);
173
174 add_option
175 ("nopal", "", 0,
176 "Don't run egg-palettize automatically on the output file, but "
177 "just output the raw egg file and all of its individual texture "
178 "images, one for each glyph.",
179 &EggMakeFont::dispatch_none, &_no_palettize);
180
181 add_option
182 ("nr", "", 0,
183 "Don't actually reduce the images after applying the scale factor, but "
184 "leave them at their inflated sizes. Presumably you will reduce "
185 "them later, for instance with egg-palettize.",
186 &EggMakeFont::dispatch_none, &_no_reduce);
187
188 add_option
189 ("gp", "pattern", 0,
190 "The pattern to be used to generate the glyph texture images. This "
191 "string will be passed to sprintf to generate the actual file name; it "
192 "should contain the string %d or %x (or some variant such as %03d) "
193 "which will be filled in with the Unicode number of each symbol. "
194 "If it is omitted, the default is based on the name of the egg file. "
195 "This is used only if -nopal is specified; in the normal case, "
196 "without -nopal, use -pp instead.",
197 &EggMakeFont::dispatch_string, nullptr, &_output_glyph_pattern);
198
199 add_option
200 ("pp", "pattern", 0,
201 "The pattern to be used to generate the palette texture images. This "
202 "string is effectively passed to egg-palettize as the -tn option, and "
203 "thus should contain %i for the palette index number. This is used "
204 "if -nopal is not specified.",
205 &EggMakeFont::dispatch_string, nullptr, &_output_palette_pattern);
206
207 add_option
208 ("palsize", "xsize,ysize", 0,
209 "Specify the size of the palette texture images. This is used if "
210 "-nopal is not specified.",
211 &EggMakeFont::dispatch_int_pair, nullptr, _palette_size);
212
213 add_option
214 ("face", "index", 0,
215 "Specify the face index of the particular face within the font file "
216 "to use. Some font files contain multiple faces, indexed beginning "
217 "at 0. The default is face 0.",
218 &EggMakeFont::dispatch_int, nullptr, &_face_index);
219
220 _fg.set(1.0, 1.0, 1.0, 1.0);
221 _bg.set(1.0, 1.0, 1.0, 0.0);
222 _interior.set(1.0, 1.0, 1.0, 1.0);
223 _pixels_per_unit = 40.0;
224 _point_size = 10.0;
225 _poly_margin = 1.0;
226 _tex_margin = 2;
227 _render_margin = 0.0;
228 _palette_size[0] = _palette_size[1] = 512;
229 _face_index = 0;
230 _generate_distance_field = false;
231
232 _text_maker = nullptr;
233 _vpool = nullptr;
234 _group = nullptr;
235 }
236
237
238 /**
239 * Does something with the additional arguments on the command line (after all
240 * the -options have been parsed). Returns true if the arguments are good,
241 * false otherwise.
242 */
243 bool EggMakeFont::
244 handle_args(ProgramBase::Args &args) {
245 if (args.empty()) {
246 nout << "Must specify name of font file on command line.\n";
247 return false;
248 }
249
250 _input_font_filename = args[0];
251 args.pop_front();
252 return EggWriter::handle_args(args);
253 }
254
255 /**
256 *
257 */
258 void EggMakeFont::
259 run() {
260 if (has_output_filename() && !get_output_filename().get_dirname().empty()) {
261 FilenameUnifier::set_rel_dirname(get_output_filename().get_dirname());
262 } else {
263 FilenameUnifier::set_rel_dirname(".");
264 }
265
266 _text_maker = new PNMTextMaker(_input_font_filename, _face_index);
267 if (!_text_maker->is_valid()) {
268 exit(1);
269 }
270
271 if (_got_interior) {
272 _no_native_aa = true;
273 }
274
275 if (!_got_scale_factor) {
276 // The default scale factor is 4 if we are not using FreeType's antialias,
277 // or 2 if we are.
278 if (_generate_distance_field) {
279 _scale_factor = 1.0;
280 } else if (_no_native_aa) {
281 _scale_factor = 4.0;
282 } else {
283 _scale_factor = 2.0;
284 }
285 }
286
287 _text_maker->set_point_size(_point_size);
288 _text_maker->set_native_antialias(!_no_native_aa);
289 _text_maker->set_interior_flag(_got_interior);
290 _text_maker->set_pixels_per_unit(_pixels_per_unit);
291 _text_maker->set_scale_factor(_scale_factor);
292
293 // The text_maker may have had to adjust the pixels per unit and the scale
294 // factor according to what the font supports.
295 _pixels_per_unit = _text_maker->get_pixels_per_unit();
296 _scale_factor = _text_maker->get_scale_factor();
297
298 if (_text_maker->get_font_pixel_size() != 0) {
299 nout << "Using " << _text_maker->get_font_pixel_size() << "-pixel font.\n";
300 }
301
302 // Now we may want to tweak the scale factor so that fonts will actually be
303 // generated big. We have to do this after we have already send the current
304 // _scale_factor through the _text_maker for validation.
305 _palettize_scale_factor = _scale_factor;
306 if (_scale_factor != 1.0 && (_no_reduce || !_no_palettize)) {
307 // If _no_reduce is true (-nr was specified), we want to keep the glyph
308 // textures full-sized, because the user asked for that.
309
310 // If _no_palettize is false (-nopal was not specified), we still want to
311 // keep the glyph textures full-sized, because the palettizer will reduce
312 // them later.
313
314 _tex_margin = (int)(_tex_margin * _scale_factor);
315 _poly_margin *= _scale_factor;
316 _pixels_per_unit *= _scale_factor;
317 _scale_factor = 1.0;
318 _text_maker->set_pixels_per_unit(_pixels_per_unit);
319 _text_maker->set_scale_factor(1.0);
320 }
321
322 if (_no_reduce) {
323 // If -nr was specified, but we're still palettizing, we don't even want
324 // to reduce the palette images. Instead, we'll generate extra-large
325 // palette images.
326 _palette_size[0] = (int)(_palette_size[0] * _palettize_scale_factor);
327 _palette_size[1] = (int)(_palette_size[1] * _palettize_scale_factor);
328 _palettize_scale_factor = 1.0;
329 }
330
331 if (_range.is_empty()) {
332 // If there's no specified range, the default is the entire ASCII set.
333 _range.add_range(0x20, 0x7e);
334
335 _range.add_singleton(0xa1); // Upside down exclamation mark
336 _range.add_singleton(0xa9); // Copyright sign
337 _range.add_singleton(0xab); // Left double angle quote
338 // _range.add_singleton(0xae); Registered sign
339 _range.add_singleton(0xb0); // Degree symbol
340 _range.add_singleton(0xb5); // Mu/micro
341 _range.add_singleton(0xb8); // Cedilla
342 _range.add_singleton(0xbb); // Right double angle quote
343 _range.add_singleton(0xbf); // Upside down question mark
344
345 _range.add_singleton(0xc6); // AE ligature
346 _range.add_singleton(0xc7); // C cedilla
347 // _range.add_singleton(0xd0); Upper-case Eth _range.add_singleton(0xd8);
348 // Upper-case O with line _range.add_singleton(0xde); Upper-case Thorn
349 _range.add_singleton(0xdf); // German Eszet
350 _range.add_singleton(0xe6); // ae ligature
351 _range.add_singleton(0xe7); // c cedilla
352 _range.add_singleton(0xf0); // Lower-case Eth
353 _range.add_singleton(0xf8); // Lower-case O with line
354 _range.add_singleton(0xfe); // Lower-case Thorn
355
356 // _range.add_singleton(0x03c0); pi
357
358 // Dotless i and j, for combining purposes.
359 _range.add_singleton(0x0131);
360 _range.add_singleton(0x0237);
361
362 // And general punctuation. These don't take up much space anyway.
363 _range.add_range(0x2018, 0x201f);
364
365 _range.add_singleton(0x2026); // Ellipses
366
367 // Also add all the combining diacritic marks.
368 _range.add_range(0x0300, 0x030f);
369 }
370 if (_output_glyph_pattern.empty()) {
371 // Create a default texture filename pattern.
372 _output_glyph_pattern = get_output_filename().get_fullpath_wo_extension() + "%03d.png";
373 }
374 if (_output_palette_pattern.empty()) {
375 // Create a default texture filename pattern.
376 _output_palette_pattern = get_output_filename().get_fullpath_wo_extension() + "_%i";
377 }
378
379 // Figure out how many channels we need based on the foreground and
380 // background colors.
381 bool needs_alpha = (_fg[3] != 1.0 || _bg[3] != 1.0 || _interior[3] != 1.0);
382 bool needs_color = (_fg[0] != _fg[1] || _fg[1] != _fg[2] ||
383 _bg[0] != _bg[1] || _bg[1] != _bg[2] ||
384 _interior[0] != _interior[1] || _interior[1] != _interior[2]);
385
386 if (needs_alpha) {
387 if (needs_color) {
388 _num_channels = 4;
389 _format = EggTexture::F_rgba;
390 } else {
391 if (_fg[0] == 1.0 && _bg[0] == 1.0 && _interior[0] == 1.0) {
392 // A special case: we only need an alpha channel. Copy the alpha data
393 // into the color channels so we can write out a one-channel image.
394 _fg[0] = _fg[1] = _fg[2] = _fg[3];
395 _bg[0] = _bg[1] = _bg[2] = _bg[3];
396 _interior[0] = _interior[1] = _interior[2] = _interior[3];
397 _num_channels = 1;
398 _format = EggTexture::F_alpha;
399 } else {
400 _num_channels = 2;
401 _format = EggTexture::F_luminance_alpha;
402 }
403 }
404 } else {
405 if (needs_color) {
406 _num_channels = 3;
407 _format = EggTexture::F_rgb;
408 } else {
409 _num_channels = 1;
410 _format = EggTexture::F_luminance;
411 }
412 }
413
414 // Create a global Palettizer object. We'll use this even if the user
415 // specified -nopal, if nothing else just to hold all of the TextureImage
416 // pointers.
417 pal = new Palettizer;
418 pal->_generated_image_pattern = _output_palette_pattern;
419 pal->_omit_solitary = false;
420 pal->_round_uvs = false;
421
422 // Generate a txa script for the palettizer. We have the palettizer reduce
423 // all of the texture images by the inverse of our scale factor.
424 char buffer[1024];
425 sprintf(buffer, ":margin 0;:coverage 1000;:background %f %f %f %f;:palette %d %d;*: %f%% keep-format",
426 _bg[0], _bg[1], _bg[2], _bg[3],
427 _palette_size[0], _palette_size[1],
428 100.0 / _palettize_scale_factor);
429 std::istringstream txa_script(buffer);
430 pal->read_txa_file(txa_script, "default script");
431
432 pal->all_params_set();
433
434 // Now create all the egg structures. We can't use _data, since we want to
435 // pass this object to the palettizer, which will try to up its reference
436 // count.
437 PT(EggData) egg_data = new EggData;
438 _group = new EggGroup();
439 egg_data->add_child(_group);
440 append_command_comment(egg_data);
441
442 _vpool = new EggVertexPool("vpool");
443 _group->add_child(_vpool);
444
445 // Make the group a sequence, as a convenience. If we view the egg file
446 // directly we can see all the characters one at a time.
447 _group->set_switch_flag(true);
448 _group->set_switch_fps(2.0);
449
450 double margin = _poly_margin;
451 if (_generate_distance_field) {
452 // Distance fields are always rendered with binary alpha.
453 _group->set_alpha_mode(EggRenderMode::AM_binary);
454
455 // Fudged to make most fonts fit on 512x256.
456 if (_poly_margin >= 1) {
457 margin += 3.5;
458 _poly_margin -= 0.5;
459 }
460
461 _text_maker->set_distance_field_radius(4);
462 }
463
464 // Also create an egg group indicating the font's design size and poly
465 // margin.
466 EggGroup *ds_group = new EggGroup("ds");
467 _group->add_child(ds_group);
468 EggVertex *vtx = make_vertex(LPoint2d(margin / _pixels_per_unit, _text_maker->get_line_height()));
469 EggPoint *point = new EggPoint;
470 ds_group->add_child(point);
471 point->add_vertex(vtx);
472
473 // Finally, add the characters, one at a time.
474 RangeIterator ri(_range);
475 do {
476 add_character(ri.get_code());
477 } while (ri.next());
478
479 // If there are extra glyphs, pick them up.
480 if (!_extra_filenames.empty()) {
481 vector_string::const_iterator si;
482 for (si = _extra_filenames.begin(); si != _extra_filenames.end(); ++si) {
483 add_extra_glyphs(*si);
484 }
485 }
486
487 if (_no_palettize) {
488 // Ok, no palettize step; just write out the egg file and all of the
489 // textures.
490 Textures::iterator ti;
491 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
492 TextureImage *texture = (*ti);
493 texture->write(texture->read_source_image());
494 }
495
496 egg_data->write_egg(get_output());
497
498 } else {
499 // Pass the generated egg structure through egg-palettize, without writing
500 // it to disk first.
501 string name = get_output_filename().get_basename();
502 EggFile *egg_file = pal->get_egg_file(name);
503 egg_file->from_command_line(egg_data, "", get_output_filename(),
504 get_exec_command());
505
506 pal->add_command_line_egg(egg_file);
507 pal->process_all(true, "");
508 pal->optimal_resize();
509 pal->generate_images(true);
510 if (!pal->write_eggs()) {
511 exit(1);
512 }
513 // pal->report_pi();
514 }
515 }
516
517 /**
518 *
519 */
520 bool EggMakeFont::
521 dispatch_range(const string &, const string &arg, void *var) {
522 RangeDescription *ip = (RangeDescription *)var;
523 return ip->parse_parameter(arg);
524 }
525
526 /**
527 * Allocates and returns a new vertex from the vertex pool representing the
528 * indicated 2-d coordinates.
529 */
530 EggVertex *EggMakeFont::
531 make_vertex(const LPoint2d &xy) {
532 return
533 _vpool->make_new_vertex(LPoint3d::origin(_coordinate_system) +
534 LVector3d::rfu(xy[0], 0.0, xy[1], _coordinate_system));
535 }
536
537 /**
538 * Generates the indicated character and adds it to the font description.
539 */
540 void EggMakeFont::
541 add_character(int code) {
542 PNMTextGlyph *glyph = _text_maker->get_glyph(code);
543 if (glyph == nullptr) {
544 nout << "No definition in font for character " << code << ".\n";
545 return;
546 }
547
548 make_geom(glyph, code);
549 }
550
551
552 /**
553 * Creates the actual geometry for the glyph.
554 */
555 void EggMakeFont::
556 make_geom(PNMTextGlyph *glyph, int character) {
557 // Create an egg group to hold the polygon.
558 string group_name = format_string(character);
559 EggGroup *group = new EggGroup(group_name);
560 _group->add_child(group);
561
562 if (glyph->get_width() != 0 && glyph->get_height() != 0) {
563 int bitmap_top = glyph->get_top();
564 int bitmap_left = glyph->get_left();
565 double tex_x_size = glyph->get_width();
566 double tex_y_size = glyph->get_height();
567
568 double poly_margin = _poly_margin;
569 double x_origin = _tex_margin;
570 double y_origin = _tex_margin;
571 double page_y_size = tex_y_size + _tex_margin * 2;
572 double page_x_size = tex_x_size + _tex_margin * 2;
573
574 // Determine the corners of the rectangle in geometric units.
575 double tex_poly_margin = poly_margin / _pixels_per_unit;
576 double origin_y = bitmap_top / _pixels_per_unit;
577 double origin_x = bitmap_left / _pixels_per_unit;
578 double top = origin_y + tex_poly_margin;
579 double left = origin_x - tex_poly_margin;
580 double bottom = origin_y - tex_y_size / _pixels_per_unit - tex_poly_margin;
581 double right = origin_x + tex_x_size / _pixels_per_unit + tex_poly_margin;
582
583 // And the corresponding corners in UV units.
584 double uv_top = 1.0f - (double)(y_origin - poly_margin) / page_y_size;
585 double uv_left = (double)(x_origin - poly_margin) / page_x_size;
586 double uv_bottom = 1.0f - (double)(y_origin + poly_margin + tex_y_size) / page_y_size;
587 double uv_right = (double)(x_origin + poly_margin + tex_x_size) / page_x_size;
588
589 // Create the vertices for the polygon.
590 EggVertex *v1 = make_vertex(LPoint2d(left, bottom));
591 EggVertex *v2 = make_vertex(LPoint2d(right, bottom));
592 EggVertex *v3 = make_vertex(LPoint2d(right, top));
593 EggVertex *v4 = make_vertex(LPoint2d(left, top));
594
595 v1->set_uv(LTexCoordd(uv_left, uv_bottom));
596 v2->set_uv(LTexCoordd(uv_right, uv_bottom));
597 v3->set_uv(LTexCoordd(uv_right, uv_top));
598 v4->set_uv(LTexCoordd(uv_left, uv_top));
599
600 EggPolygon *poly = new EggPolygon();
601 group->add_child(poly);
602 poly->set_texture(get_tref(glyph, character));
603
604 poly->add_vertex(v1);
605 poly->add_vertex(v2);
606 poly->add_vertex(v3);
607 poly->add_vertex(v4);
608 }
609
610 // Now create a single point where the origin of the next character will be.
611
612 EggVertex *v0 = make_vertex(LPoint2d(glyph->get_advance() / _pixels_per_unit + _render_margin, 0.0));
613 EggPoint *point = new EggPoint;
614 group->add_child(point);
615 point->add_vertex(v0);
616 }
617
618 /**
619 * Returns the egg texture reference for a particular glyph, creating it if it
620 * has not already been created.
621 */
622 EggTexture *EggMakeFont::
623 get_tref(PNMTextGlyph *glyph, int character) {
624 TRefs::iterator ti = _trefs.find(glyph);
625 if (ti != _trefs.end()) {
626 return (*ti).second;
627 }
628
629 EggTexture *tref = make_tref(glyph, character);
630 _trefs[glyph] = tref;
631 return tref;
632 }
633
634 /**
635 * Generates a texture image for the indicated glyph, and returns its egg
636 * reference.
637 */
638 EggTexture *EggMakeFont::
639 make_tref(PNMTextGlyph *glyph, int character) {
640 char buffer[1024];
641 sprintf(buffer, _output_glyph_pattern.c_str(), character);
642
643 Filename texture_filename = buffer;
644 PNMImage image(glyph->get_width() + _tex_margin * 2,
645 glyph->get_height() + _tex_margin * 2, _num_channels);
646 image.fill(_bg[0], _bg[1], _bg[2]);
647 if (image.has_alpha()) {
648 image.alpha_fill(_bg[3]);
649 }
650 if (_got_interior) {
651 glyph->place(image, -glyph->get_left() + _tex_margin,
652 glyph->get_top() + _tex_margin, _fg, _interior);
653 } else {
654 glyph->place(image, -glyph->get_left() + _tex_margin,
655 glyph->get_top() + _tex_margin, _fg);
656 }
657
658 // We don't write the image to disk immediately, since it might just get
659 // palettized. But we do record it in a TextureImage object within the
660 // global Palettizer, so that it may be written out later.
661
662 string name = texture_filename.get_basename_wo_extension();
663 TextureImage *texture = pal->get_texture(name);
664 _textures.push_back(texture);
665 texture->set_filename("", texture_filename);
666 SourceTextureImage *source = texture->get_source(texture_filename, "", 0);
667 texture->set_source_image(image);
668 source->set_header(image);
669
670 EggTexture *tref = new EggTexture(name, texture_filename);
671 tref->set_format(_format);
672 tref->set_wrap_mode(EggTexture::WM_clamp);
673 tref->set_minfilter(EggTexture::FT_linear_mipmap_linear);
674 tref->set_magfilter(EggTexture::FT_linear);
675 tref->set_quality_level(EggTexture::QL_best);
676
677 return tref;
678 }
679
680 /**
681 * Reads the indicated filename and adds any numbered groups into the current
682 * egg file.
683 */
684 void EggMakeFont::
685 add_extra_glyphs(const Filename &extra_filename) {
686 PT(EggData) extra_data = new EggData;
687
688 if (!extra_data->read(extra_filename)) {
689 return;
690 }
691
692 _group->steal_children(*extra_data);
693 }
694
695 /**
696 * Recursively searches for numbered groups in the indicated egg file, and
697 * copies them to the current egg file.
698 */
699 void EggMakeFont::
700 r_add_extra_glyphs(EggGroupNode *egg_group) {
701 if (egg_group->is_of_type(EggGroup::get_class_type())) {
702 EggGroup *group = DCAST(EggGroup, egg_group);
703 if (is_numeric(group->get_name())) {
704 EggGroup *new_group = new EggGroup(group->get_name());
705 _group->add_child(new_group);
706 new_group->steal_children(*group);
707 return;
708 }
709 }
710
711 EggGroupNode::iterator ci;
712 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
713 EggNode *child = (*ci);
714 if (child->is_of_type(EggGroupNode::get_class_type())) {
715 r_add_extra_glyphs(DCAST(EggGroupNode, child));
716 }
717 }
718 }
719
720 /**
721 * Returns true if the indicated string is all numeric digits, false
722 * otherwise.
723 */
724 bool EggMakeFont::
725 is_numeric(const string &str) {
726 if (str.empty()) {
727 return false;
728 }
729
730 string::const_iterator si;
731 for (si = str.begin(); si != str.end(); ++si) {
732 if (!isdigit(*si)) {
733 return false;
734 }
735 }
736
737 return true;
738 }
739
740 int main(int argc, char *argv[]) {
741 EggMakeFont prog;
742 prog.parse_command_line(argc, argv);
743 prog.run();
744 return 0;
745 }
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
EggFile
This represents a single egg file known to the palettizer.
Definition: eggFile.h:36
EggFile::from_command_line
bool from_command_line(EggData *data, const Filename &source_filename, const Filename &dest_filename, const std::string &egg_comment)
Accepts the information about the egg file as supplied from the command line.
Definition: eggFile.cxx:57
EggGroupNode
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
EggGroupNode::add_child
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
Definition: eggGroupNode.cxx:243
EggGroupNode::steal_children
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
Definition: eggGroupNode.cxx:278
EggGroup
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
EggMakeFont
This program uses FreeType to generate an egg file and a series of texture images from a font file in...
Definition: eggMakeFont.h:38
EggNode
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:36
EggPoint
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:25
EggPolygon
A single polygon.
Definition: eggPolygon.h:24
EggPrimitive::set_texture
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:116
EggPrimitive::add_vertex
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
Definition: eggPrimitive.cxx:654
EggRenderMode::set_alpha_mode
void set_alpha_mode(AlphaMode mode)
Specifies precisely how the transparency for this geometry should be achieved, or if it should be use...
Definition: eggRenderMode.I:89
EggTexture
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
EggVertexPool
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertexPool::make_new_vertex
EggVertex * make_new_vertex()
Allocates and returns a new vertex from the pool.
Definition: eggVertexPool.I:37
EggVertex
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
EggVertex::set_uv
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:193
EggWriter
This is the base class for a program that generates an egg file output, but doesn't read any for inpu...
Definition: eggWriter.h:28
FilenameUnifier::set_rel_dirname
static void set_rel_dirname(const Filename &rel_dirname)
Sets the name of the directory that texture filenames will be written relative to,...
Definition: filenameUnifier.cxx:49
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::get_basename
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
Filename::get_fullpath_wo_extension
std::string get_fullpath_wo_extension() const
Returns the full filename–directory and basename parts–except for the extension.
Definition: filename.I:377
Filename::get_basename_wo_extension
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
ImageFile::write
bool write(const PNMImage &image) const
Writes out the image in the indicated PNMImage to the _filename and/or _alpha_filename.
Definition: imageFile.cxx:339
ImageFile::set_filename
bool set_filename(PaletteGroup *group, const std::string &basename)
Sets the filename, and if applicable, the alpha_filename, from the indicated basename.
Definition: imageFile.cxx:150
PNMImage
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
PNMTextGlyph
A single glyph in a PNMTextMaker.
Definition: pnmTextGlyph.h:25
PNMTextGlyph::get_top
int get_top() const
Returns the y coordinate of the topmost pixel in the glyph.
Definition: pnmTextGlyph.I:51
PNMTextGlyph::get_advance
int get_advance() const
Returns the number of pixels by which the pen should be advanced after rendering this glyph.
Definition: pnmTextGlyph.I:19
PNMTextGlyph::get_width
int get_width() const
Returns the width of the glyph in pixels.
Definition: pnmTextGlyph.I:67
PNMTextGlyph::get_left
int get_left() const
Returns the x coordinate of the leftmost pixel in the glyph.
Definition: pnmTextGlyph.I:27
PNMTextGlyph::place
void place(PNMImage &dest_image, int xp, int yp, const LColor &fg)
Copies the glyph to the indicated destination image at the indicated origin.
Definition: pnmTextGlyph.cxx:46
PNMTextGlyph::get_height
int get_height() const
Returns the height of the glyph in pixels.
Definition: pnmTextGlyph.I:59
PNMTextMaker
This object uses the Freetype library to generate text directly into an image.
Definition: pnmTextMaker.h:35
PNMTextMaker::get_glyph
PNMTextGlyph * get_glyph(int character)
Returns the glyph for the indicated index, or NULL if it is not defined in the font.
Definition: pnmTextMaker.cxx:140
PNMTextMaker::set_distance_field_radius
void set_distance_field_radius(int radius)
If this is set to something other than 0, Panda will generate a signed distance field with the given ...
Definition: pnmTextMaker.I:107
PNMTextMaker::set_interior_flag
void set_interior_flag(bool interior_flag)
Sets the flag that indicates whether the interior of hollow fonts is identified as a preprocess as ea...
Definition: pnmTextMaker.I:49
PNMTextMaker::is_valid
bool is_valid() const
Returns true if the PNMTextMaker is valid and ready to generate text, false otherwise.
Definition: pnmTextMaker.I:19
Palettizer
This is the main engine behind egg-palettize.
Definition: palettizer.h:39
Palettizer::process_all
void process_all(bool force_texture_read, const Filename &state_filename)
Reprocesses all textures known.
Definition: palettizer.cxx:514
Palettizer::get_texture
TextureImage * get_texture(const std::string &name)
Returns the TextureImage with the given name.
Definition: palettizer.cxx:838
Palettizer::optimal_resize
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
Definition: palettizer.cxx:606
Palettizer::all_params_set
void all_params_set()
Called after all command line parameters have been set up, this is a hook to do whatever initializati...
Definition: palettizer.cxx:406
Palettizer::get_egg_file
EggFile * get_egg_file(const std::string &name)
Returns the EggFile with the given name.
Definition: palettizer.cxx:749
Palettizer::add_command_line_egg
void add_command_line_egg(EggFile *egg_file)
Adds the indicated EggFile to the list of eggs that are considered to have been read on the command l...
Definition: palettizer.cxx:784
Palettizer::write_eggs
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
Definition: palettizer.cxx:714
Palettizer::read_txa_file
void read_txa_file(std::istream &txa_file, const std::string &txa_filename)
Reads in the .txa file and keeps it ready for matching textures and egg files.
Definition: palettizer.cxx:353
Palettizer::generate_images
void generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories.
Definition: palettizer.cxx:633
ProgramBase::get_exec_command
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
Definition: programBase.cxx:467
ProgramBase::parse_command_line
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
Definition: programBase.cxx:286
RangeDescription
This describes a sparse range of Unicode character codes for conversion that may be specified on the ...
Definition: rangeDescription.h:24
RangeDescription::is_empty
bool is_empty() const
Returns true if there are no codes described in the range.
Definition: rangeDescription.I:34
RangeDescription::parse_parameter
bool parse_parameter(const std::string &param)
Parses a string of comma- and hyphen-delimited unicode values, in decimal and/or hex,...
Definition: rangeDescription.cxx:34
RangeIterator
Walks through all the Unicode characters described by a RangeDescription class.
Definition: rangeIterator.h:26
SourceTextureImage
This is a texture image reference as it appears in an egg file: the source image of the texture.
Definition: sourceTextureImage.h:28
SourceTextureImage::set_header
void set_header(const PNMImageHeader &header)
Sets the header information associated with this image, as if it were loaded from the disk.
Definition: sourceTextureImage.cxx:127
TextureImage
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
TextureImage::set_source_image
void set_source_image(const PNMImage &image)
Accepts the indicated source image as if it had been read from disk.
Definition: textureImage.cxx:742
TextureImage::get_source
SourceTextureImage * get_source(const Filename &filename, const Filename &alpha_filename, int alpha_file_channel)
Returns the SourceTextureImage corresponding to the given filename(s).
Definition: textureImage.cxx:519
TextureImage::read_source_image
const PNMImage & read_source_image()
Reads in the original image, if it has not already been read, and returns it.
Definition: textureImage.cxx:709
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
WithOutputFile::get_output_filename
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
Definition: withOutputFile.cxx:131
WithOutputFile::has_output_filename
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
Definition: withOutputFile.cxx:122
WithOutputFile::get_output
std::ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout,...
Definition: withOutputFile.cxx:50
pdeque< std::string >
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggGroup.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggMakeFont.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPoint.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPolygon.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggTexture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggVertexPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggVertex.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
filenameUnifier.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
palettizer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmTextGlyph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmTextMaker.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
rangeIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
sourceTextureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
textureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.