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()) {
262  } else {
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 }
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
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.
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
TextureImage * get_texture(const std::string &name)
Returns the TextureImage with the given name.
Definition: palettizer.cxx:838
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_...
This is the main engine behind egg-palettize.
Definition: palettizer.h:39
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
bool is_empty() const
Returns true if there are no codes described in the range.
SourceTextureImage * get_source(const Filename &filename, const Filename &alpha_filename, int alpha_file_channel)
Returns the SourceTextureImage corresponding to the given filename(s).
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
void process_all(bool force_texture_read, const Filename &state_filename)
Reprocesses all textures known.
Definition: palettizer.cxx:514
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:116
bool parse_parameter(const std::string &param)
Parses a string of comma- and hyphen-delimited unicode values, in decimal and/or hex,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Walks through all the Unicode characters described by a RangeDescription class.
Definition: rangeIterator.h:26
This program uses FreeType to generate an egg file and a series of texture images from a font file in...
Definition: eggMakeFont.h:38
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
This object uses the Freetype library to generate text directly into an image.
Definition: pnmTextMaker.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:25
int get_top() const
Returns the y coordinate of the topmost pixel in the glyph.
Definition: pnmTextGlyph.I:51
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggVertex * make_new_vertex()
Allocates and returns a new vertex from the pool.
Definition: eggVertexPool.I:37
int get_height() const
Returns the height of the glyph in pixels.
Definition: pnmTextGlyph.I:59
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
int get_left() const
Returns the x coordinate of the leftmost pixel in the glyph.
Definition: pnmTextGlyph.I:27
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
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
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
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
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
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_width() const
Returns the width of the glyph in pixels.
Definition: pnmTextGlyph.I:67
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
Definition: palettizer.cxx:714
void set_header(const PNMImageHeader &header)
Sets the header information associated with this image, as if it were loaded from the disk.
std::string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
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
void generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories.
Definition: palettizer.cxx:633
This is a texture image reference as it appears in an egg file: the source image of the texture.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single polygon.
Definition: eggPolygon.h:24
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
void set_source_image(const PNMImage &image)
Accepts the indicated source image as if it had been read from disk.
bool is_valid() const
Returns true if the PNMTextMaker is valid and ready to generate text, false otherwise.
Definition: pnmTextMaker.I:19
const PNMImage & read_source_image()
Reads in the original image, if it has not already been read, and returns it.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A single glyph in a PNMTextMaker.
Definition: pnmTextGlyph.h:25
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
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
Definition: palettizer.cxx:606
void fill(float red, float green, float blue)
Sets the entire image (except the alpha channel) to the given color.
Definition: pnmImage.I:157
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout,...
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
Definition: eggVertex.I:193
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
This describes a sparse range of Unicode character codes for conversion that may be specified on the ...
std::string get_fullpath_wo_extension() const
Returns the full filename–directory and basename parts–except for the extension.
Definition: filename.I:377
This represents a single egg file known to the palettizer.
Definition: eggFile.h:36
PNMTextGlyph * get_glyph(int character)
Returns the glyph for the indicated index, or NULL if it is not defined in the font.
static void set_rel_dirname(const Filename &rel_dirname)
Sets the name of the directory that texture filenames will be written relative to,...
EggFile * get_egg_file(const std::string &name)
Returns the EggFile with the given name.
Definition: palettizer.cxx:749