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 }
PNMTextGlyph::get_height
int get_height() const
Returns the height of the glyph in pixels.
Definition: pnmTextGlyph.I:59
eggData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
pnmTextMaker.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
eggVertexPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggFile
This represents a single egg file known to the palettizer.
Definition: eggFile.h:36
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPoint.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
EggVertexPool::make_new_vertex
EggVertex * make_new_vertex()
Allocates and returns a new vertex from the pool.
Definition: eggVertexPool.I:37
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
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
RangeIterator
Walks through all the Unicode characters described by a RangeDescription class.
Definition: rangeIterator.h:26
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
eggMakeFont.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Palettizer::get_egg_file
EggFile * get_egg_file(const std::string &name)
Returns the EggFile with the given name.
Definition: palettizer.cxx:749
Palettizer
This is the main engine behind egg-palettize.
Definition: palettizer.h:39
EggGroupNode
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
eggTexture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Palettizer::write_eggs
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
Definition: palettizer.cxx:714
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
textureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
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
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
SourceTextureImage
This is a texture image reference as it appears in an egg file: the source image of the texture.
Definition: sourceTextureImage.h:28
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:274
EggGroupNode::steal_children
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
Definition: eggGroupNode.cxx:278
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
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:455
RangeDescription::is_empty
bool is_empty() const
Returns true if there are no codes described in the range.
Definition: rangeDescription.I:34
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
filenameUnifier.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
EggVertex
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
PNMTextMaker
This object uses the Freetype library to generate text directly into an image.
Definition: pnmTextMaker.h:35
palettizer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggPolygon
A single polygon.
Definition: eggPolygon.h:24
pdeque< std::string >
eggVertex.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Palettizer::optimal_resize
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
Definition: palettizer.cxx:606
PNMTextGlyph::get_width
int get_width() const
Returns the width of the glyph in pixels.
Definition: pnmTextGlyph.I:67
EggPrimitive::set_texture
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
Definition: eggPrimitive.I:116
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
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
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
PNMTextGlyph
A single glyph in a PNMTextMaker.
Definition: pnmTextGlyph.h:25
sourceTextureImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PNMTextGlyph::get_left
int get_left() const
Returns the x coordinate of the leftmost pixel in the glyph.
Definition: pnmTextGlyph.I:27
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
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
EggTexture
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
RangeDescription
This describes a sparse range of Unicode character codes for conversion that may be specified on the ...
Definition: rangeDescription.h:24
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
EggVertexPool
A collection of vertices.
Definition: eggVertexPool.h:41
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
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::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
EggNode
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
eggFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroup
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
EggGroupNode::add_child
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
Definition: eggGroupNode.cxx:243
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
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
EggPoint
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:25
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.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename::get_basename
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
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
eggGroup.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
rangeIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMTextGlyph::get_top
int get_top() const
Returns the y coordinate of the topmost pixel in the glyph.
Definition: pnmTextGlyph.I:51
TextureImage
This represents a single source texture that is referenced by one or more egg files.
Definition: textureImage.h:46
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
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
eggPolygon.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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