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