Panda3D

eggMakeFont.cxx

00001 // Filename: eggMakeFont.cxx
00002 // Created by:  drose (16Feb01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "eggMakeFont.h"
00016 #include "rangeIterator.h"
00017 #include "palettizer.h"
00018 #include "filenameUnifier.h"
00019 #include "eggFile.h"
00020 #include "textureImage.h"
00021 #include "sourceTextureImage.h"
00022 #include "pnmTextMaker.h"
00023 #include "pnmTextGlyph.h"
00024 #include "eggData.h"
00025 #include "eggGroup.h"
00026 #include "eggPoint.h"
00027 #include "eggPolygon.h"
00028 #include "eggTexture.h"
00029 #include "eggVertexPool.h"
00030 #include "eggVertex.h"
00031 #include "string_utils.h"
00032 #include "dcast.h"
00033 #include "pystub.h"
00034 
00035 #include <ctype.h>
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: EggMakeFont::Constructor
00039 //       Access: Public
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 EggMakeFont::
00043 EggMakeFont() : EggWriter(true, false) {
00044   set_program_description
00045     ("egg-mkfont uses the FreeType library to generate an egg file "
00046      "and a series of texture images from a font file "
00047      "input, such as a TTF file.  The resulting egg file "
00048      "can be loaded in Panda as a font for rendering text, even "
00049      "if FreeType is not compiled into the executing Panda.\n\n"
00050 
00051      "egg-mkfont will normally run the generated egg file through "
00052      "egg-palettize automatically as part of the generation process.  "
00053      "This collects the individual glyph textures into a small number "
00054      "of texture maps.  If you intend to run the font through egg-palettize "
00055      "yourself later, you may choose to omit this step.");
00056 
00057   clear_runlines();
00058   add_runline("[opts] -o output.egg font");
00059   add_runline("[opts] font output.egg");
00060 
00061   add_option
00062     ("fg", "r,g,b[,a]", 0,
00063      "Specifies the foreground color of the generated texture map.  The "
00064      "default is white: 1,1,1,1, which leads to the most flexibility "
00065      "as the color can be modulated at runtime to any suitable color.",
00066      &EggMakeFont::dispatch_color, NULL, &_fg[0]);
00067 
00068   add_option
00069     ("bg", "r,g,b[,a]", 0,
00070      "Specifies the background color of the generated texture map.  The "
00071      "default is transparent: 1,1,1,0, which allows the text to be "
00072      "visible against any color background by placing a polygon of a "
00073      "suitable color behind it.  If the alpha component of either -fg "
00074      "or -bg is not 1, the generated texture images will include an "
00075      "alpha component; if both colors specify an alpha component of 1 "
00076      "(or do not specify an alpha compenent), then the generated images "
00077      "will not include an alpha component.",
00078      &EggMakeFont::dispatch_color, NULL, &_bg[0]);
00079 
00080   add_option
00081     ("interior", "r,g,b[,a]", 0,
00082      "Specifies the color to render the interior part of a hollow font.  "
00083      "This is a special effect that involves analysis of the bitmap after "
00084      "the font has been rendered, and so is more effective when the pixel "
00085      "size is large.  It also implies -noaa (but you can use a scale "
00086      "factor with -sf to achieve antialiasing).",
00087      &EggMakeFont::dispatch_color, &_got_interior, &_interior[0]);
00088 
00089   add_option
00090     ("chars", "range", 0,
00091      "Specifies the characters of the font that are used.  The range "
00092      "specification may include combinations of decimal or hex unicode "
00093      "values (where hex values are identified with a leading 0x), separated "
00094      "by commas and hyphens to indicate ranges, e.g. '32-126,0xfa0-0xfff'.  "
00095      "It also may specify ranges of ASCII characters by enclosing them "
00096      "within square brackets, e.g. '[A-Za-z0-9]'.  If this is not specified, "
00097      "the default is the set of ASCII characters.",
00098      &EggMakeFont::dispatch_range, NULL, &_range);
00099 
00100   add_option
00101     ("extra", "file.egg", 0,
00102      "Specifies additional externally-painted glyphs to mix into the "
00103      "generated egg file.  The named egg file is expected to contain one "
00104      "or more groups, each of which is named with the decimal unicode "
00105      "number of a character and should contain one polygon.  These groups "
00106      "are simply copied into the output egg file as if they were generated "
00107      "locally.  This option may be repeated.",
00108      &EggMakeFont::dispatch_vector_string, NULL, &_extra_filenames);
00109 
00110   add_option
00111     ("ppu", "pixels", 0,
00112      "Specify the pixels per unit.  This is the number of pixels in the "
00113      "generated texture map that are used for each onscreen unit (or each "
00114      "10 points of font; see -ps).  Setting this number larger results in "
00115      "an easier-to-read font, but at the cost of more texture memory.  "
00116      "The default is 30.",
00117      &EggMakeFont::dispatch_double, NULL, &_pixels_per_unit);
00118 
00119   add_option
00120     ("ps", "size", 0,
00121      "Specify the point size of the resulting font.  This controls the "
00122      "apparent size of the font when it is rendered onscreen.  By convention, "
00123      "a 10 point font is 1 screen unit high, so the default is 10.",
00124      &EggMakeFont::dispatch_double, NULL, &_point_size);
00125 
00126   add_option
00127     ("pm", "n", 0,
00128      "The number of extra pixels around a single character in the "
00129      "generated polygon.  This may be a floating-point number.  The "
00130      "default is 1.",
00131      &EggMakeFont::dispatch_double, NULL, &_poly_margin);
00132 
00133   add_option
00134     ("tm", "n", 0,
00135      "The number of extra pixels around each character in the texture map.  "
00136      "This may only be an integer.  The default is 2.  This is meaningful "
00137      "when -nopal is also used; in the normal case, use -pm to control "
00138      "both the polygon size and the texture map spacing.",
00139      &EggMakeFont::dispatch_int, NULL, &_tex_margin);
00140 
00141   add_option
00142     ("rm", "n", 0,
00143      "The amount of padding in screen units to place around the glyph when "
00144      "rendered.  This differs from -pm in that it has no effect on the "
00145      "generated texture map, only on the generated egg.  Use this in order to "
00146      "space the characters out in case they appear to be too close together "
00147      "when rendered. The default is 0.",
00148      &EggMakeFont::dispatch_double, NULL, &_render_margin);
00149 
00150   add_option
00151     ("sf", "factor", 0,
00152      "The scale factor of the generated image.  This is the factor by which "
00153      "the font image is generated oversized, then reduced to its final size, "
00154      "to improve antialiasing.  If the specified font contains one "
00155      "or more fixed-size fonts instead of a scalable font, the scale factor "
00156      "may be automatically adjusted as necessary to scale the closest-"
00157      "matching font to the desired pixel size.  The default is 2.",
00158      &EggMakeFont::dispatch_double, &_got_scale_factor, &_scale_factor);
00159 
00160   add_option
00161     ("noaa", "", 0,
00162      "Disable low-level antialiasing by the Freetype library.  "
00163      "This is unrelated to the antialiasing that is applied due to the "
00164      "scale factor specified by -sf; you may have either one, neither, or "
00165      "both kinds of antialiasing enabled.",
00166      &EggMakeFont::dispatch_none, &_no_native_aa);
00167 
00168   add_option
00169     ("nopal", "", 0,
00170      "Don't run egg-palettize automatically on the output file, but "
00171      "just output the raw egg file and all of its individual texture "
00172      "images, one for each glyph.",
00173      &EggMakeFont::dispatch_none, &_no_palettize);
00174 
00175   add_option
00176     ("nr", "", 0,
00177      "Don't actually reduce the images after applying the scale factor, but "
00178      "leave them at their inflated sizes.  Presumably you will reduce "
00179      "them later, for instance with egg-palettize.",
00180      &EggMakeFont::dispatch_none, &_no_reduce);
00181 
00182   add_option
00183     ("gp", "pattern", 0,
00184      "The pattern to be used to generate the glyph texture images.  This "
00185      "string will be passed to sprintf to generate the actual file name; it "
00186      "should contain the string %d or %x (or some variant such as %03d) "
00187      "which will be filled in with the Unicode number of each symbol.  "
00188      "If it is omitted, the default is based on the name of the egg file.  "
00189      "This is used only if -nopal is specified; in the normal case, "
00190      "without -nopal, use -pp instead.",
00191      &EggMakeFont::dispatch_string, NULL, &_output_glyph_pattern);
00192 
00193   add_option
00194     ("pp", "pattern", 0,
00195      "The pattern to be used to generate the palette texture images.  This "
00196      "string is effectively passed to egg-palettize as the -tn option, and "
00197      "thus should contain %i for the palette index number.  This is used "
00198      "if -nopal is not specified.",
00199      &EggMakeFont::dispatch_string, NULL, &_output_palette_pattern);
00200 
00201   add_option
00202     ("palsize", "xsize,ysize", 0,
00203      "Specify the size of the palette texture images.  This is used if "
00204      "-nopal is not specified.",
00205      &EggMakeFont::dispatch_int_pair, NULL, _palette_size);
00206   
00207   add_option
00208     ("face", "index", 0,
00209      "Specify the face index of the particular face within the font file "
00210      "to use.  Some font files contain multiple faces, indexed beginning "
00211      "at 0.  The default is face 0.",
00212      &EggMakeFont::dispatch_int, NULL, &_face_index);
00213 
00214   _fg.set(1.0, 1.0, 1.0, 1.0);
00215   _bg.set(1.0, 1.0, 1.0, 0.0);
00216   _interior.set(1.0, 1.0, 1.0, 1.0);
00217   _pixels_per_unit = 30.0;
00218   _point_size = 10.0;
00219   _poly_margin = 1.0;
00220   _tex_margin = 2;
00221   _render_margin = 0.0;
00222   _palette_size[0] = _palette_size[1] = 256;
00223   _face_index = 0;
00224 
00225   _text_maker = NULL;
00226   _vpool = NULL;
00227   _group = NULL;
00228 }
00229 
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: EggMakeFont::handle_args
00233 //       Access: Protected, Virtual
00234 //  Description: Does something with the additional arguments on the
00235 //               command line (after all the -options have been
00236 //               parsed).  Returns true if the arguments are good,
00237 //               false otherwise.
00238 ////////////////////////////////////////////////////////////////////
00239 bool EggMakeFont::
00240 handle_args(ProgramBase::Args &args) {
00241   if (args.empty()) {
00242     nout << "Must specify name of font file on command line.\n";
00243     return false;
00244   }
00245 
00246   _input_font_filename = args[0];
00247   args.pop_front();
00248   return EggWriter::handle_args(args);
00249 }
00250 
00251 ////////////////////////////////////////////////////////////////////
00252 //     Function: EggMakeFont::run
00253 //       Access: Public
00254 //  Description:
00255 ////////////////////////////////////////////////////////////////////
00256 void EggMakeFont::
00257 run() {
00258   if (has_output_filename() && !get_output_filename().get_dirname().empty()) {
00259     FilenameUnifier::set_rel_dirname(get_output_filename().get_dirname());
00260   } else {
00261     FilenameUnifier::set_rel_dirname(".");
00262   }
00263 
00264   _text_maker = new PNMTextMaker(_input_font_filename, _face_index);
00265   if (!_text_maker->is_valid()) {
00266     exit(1);
00267   }
00268 
00269   if (_got_interior) {
00270     _no_native_aa = true;
00271   }
00272 
00273   if (!_got_scale_factor) {
00274     // The default scale factor is 4 if we are not using FreeType's
00275     // antialias, or 2 if we are.
00276     if (_no_native_aa) {
00277       _scale_factor = 4.0;
00278     } else {
00279       _scale_factor = 2.0;
00280     }
00281   }
00282 
00283   _text_maker->set_point_size(_point_size);
00284   _text_maker->set_native_antialias(!_no_native_aa);
00285   _text_maker->set_interior_flag(_got_interior);
00286   _text_maker->set_pixels_per_unit(_pixels_per_unit);
00287   _text_maker->set_scale_factor(_scale_factor);
00288 
00289   // The text_maker may have had to adjust the pixels per unit and the
00290   // scale factor according to what the font supports.
00291   _pixels_per_unit = _text_maker->get_pixels_per_unit();
00292   _scale_factor = _text_maker->get_scale_factor();
00293 
00294   if (_text_maker->get_font_pixel_size() != 0) {
00295     nout << "Using " << _text_maker->get_font_pixel_size() << "-pixel font.\n";
00296   }
00297 
00298   // Now we may want to tweak the scale factor so that fonts will
00299   // actually be generated big.  We have to do this after we have
00300   // already send the current _scale_factor through the _text_maker
00301   // for validation.
00302   _palettize_scale_factor = _scale_factor;
00303   if (_scale_factor != 1.0 && (_no_reduce || !_no_palettize)) {
00304     // If _no_reduce is true (-nr was specified), we want to keep the
00305     // glyph textures full-sized, because the user asked for that.
00306 
00307     // If _no_palettize is false (-nopal was not specified), we still
00308     // want to keep the glyph textures full-sized, because the
00309     // palettizer will reduce them later.
00310 
00311     _tex_margin = (int)(_tex_margin * _scale_factor);
00312     _poly_margin *= _scale_factor;
00313     _pixels_per_unit *= _scale_factor;
00314     _scale_factor = 1.0;
00315     _text_maker->set_pixels_per_unit(_pixels_per_unit);
00316     _text_maker->set_scale_factor(1.0);
00317   }
00318 
00319   if (_no_reduce) {
00320     // If -nr was specified, but we're still palettizing, we don't
00321     // even want to reduce the palette images.  Instead, we'll
00322     // generate extra-large palette images.
00323     _palette_size[0] = (int)(_palette_size[0] * _palettize_scale_factor);
00324     _palette_size[1] = (int)(_palette_size[1] * _palettize_scale_factor);
00325     _palettize_scale_factor = 1.0;
00326   }
00327 
00328   if (_range.is_empty()) {
00329     // If there's no specified range, the default is the entire ASCII
00330     // set.
00331     _range.add_range(0x20, 0x7e);
00332   }
00333   if (_output_glyph_pattern.empty()) {
00334     // Create a default texture filename pattern.
00335     _output_glyph_pattern = get_output_filename().get_fullpath_wo_extension() + "%03d.png";
00336   }
00337   if (_output_palette_pattern.empty()) {
00338     // Create a default texture filename pattern.
00339     _output_palette_pattern = get_output_filename().get_fullpath_wo_extension() + "_%i";
00340   }
00341 
00342   // Figure out how many channels we need based on the foreground and
00343   // background colors.
00344   bool needs_alpha = (_fg[3] != 1.0 || _bg[3] != 1.0 || _interior[3] != 1.0);
00345   bool needs_color = (_fg[0] != _fg[1] || _fg[1] != _fg[2] ||
00346                       _bg[0] != _bg[1] || _bg[1] != _bg[2] ||
00347                       _interior[0] != _interior[1] || _interior[1] != _interior[2]);
00348 
00349   if (needs_alpha) {
00350     if (needs_color) {
00351       _num_channels = 4;
00352       _format = EggTexture::F_rgba;
00353     } else {
00354       if (_fg[0] == 1.0 && _bg[0] == 1.0 && _interior[0] == 1.0) {
00355         // A special case: we only need an alpha channel.  Copy the
00356         // alpha data into the color channels so we can write out a
00357         // one-channel image.
00358         _fg[0] = _fg[1] = _fg[2] = _fg[3];
00359         _bg[0] = _bg[1] = _bg[2] = _bg[3];
00360         _interior[0] = _interior[1] = _interior[2] = _interior[3];
00361         _num_channels = 1;
00362         _format = EggTexture::F_alpha;
00363       } else {
00364         _num_channels = 2;
00365         _format = EggTexture::F_luminance_alpha;
00366       }
00367     }
00368   } else {
00369     if (needs_color) {
00370       _num_channels = 3;
00371       _format = EggTexture::F_rgb;
00372     } else {
00373       _num_channels = 1;
00374       _format = EggTexture::F_luminance;
00375     }
00376   }      
00377 
00378   // Create a global Palettizer object.  We'll use this even if the
00379   // user specified -nopal, if nothing else just to hold all of the
00380   // TextureImage pointers.
00381   pal = new Palettizer;
00382   pal->_generated_image_pattern = _output_palette_pattern;
00383   pal->_omit_solitary = false;
00384   pal->_round_uvs = false;
00385 
00386   // Generate a txa script for the palettizer.  We have the palettizer
00387   // reduce all of the texture images by the inverse of our scale
00388   // factor.
00389   char buffer[1024];
00390   sprintf(buffer, ":margin 0;:coverage 1000;:background %f %f %f %f;:palette %d %d;*: %f%% keep-format", 
00391           _bg[0], _bg[1], _bg[2], _bg[3],
00392           _palette_size[0], _palette_size[1],
00393           100.0 / _palettize_scale_factor);
00394   istringstream txa_script(buffer);
00395   pal->read_txa_file(txa_script, "default script");
00396 
00397   pal->all_params_set();
00398 
00399   // Now create all the egg structures.  We can't use _data, since we
00400   // want to pass this object to the palettizer, which will try to up
00401   // its reference count.
00402   PT(EggData) egg_data = new EggData;
00403   _group = new EggGroup();
00404   egg_data->add_child(_group);
00405   append_command_comment(egg_data);
00406 
00407   _vpool = new EggVertexPool("vpool");
00408   _group->add_child(_vpool);
00409 
00410   // Make the group a sequence, as a convenience.  If we view the
00411   // egg file directly we can see all the characters one at a time.
00412   _group->set_switch_flag(true);
00413   _group->set_switch_fps(2.0);
00414 
00415   // Also create an egg group indicating the font's design size.
00416   EggGroup *ds_group = new EggGroup("ds");
00417   _group->add_child(ds_group);
00418   EggVertex *vtx = make_vertex(LPoint2d(0.0, _text_maker->get_line_height()));
00419   EggPoint *point = new EggPoint;
00420   ds_group->add_child(point);
00421   point->add_vertex(vtx);
00422 
00423   // Finally, add the characters, one at a time.
00424   RangeIterator ri(_range);
00425   do {
00426     add_character(ri.get_code());
00427   } while (ri.next());
00428 
00429   // If there are extra glyphs, pick them up.
00430   if (!_extra_filenames.empty()) {
00431     vector_string::const_iterator si;
00432     for (si = _extra_filenames.begin(); si != _extra_filenames.end(); ++si) {
00433       add_extra_glyphs(*si);
00434     }
00435   }
00436 
00437   if (_no_palettize) {
00438     // Ok, no palettize step; just write out the egg file and all of
00439     // the textures.
00440     Textures::iterator ti;
00441     for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
00442       TextureImage *texture = (*ti);
00443       texture->write(texture->read_source_image());
00444     }
00445 
00446     egg_data->write_egg(get_output());
00447 
00448   } else {
00449     // Pass the generated egg structure through egg-palettize, without
00450     // writing it to disk first.
00451     string name = get_output_filename().get_basename();
00452     EggFile *egg_file = pal->get_egg_file(name);
00453     egg_file->from_command_line(egg_data, "", get_output_filename(),
00454                                 get_exec_command());
00455 
00456     pal->add_command_line_egg(egg_file);
00457     pal->process_all(true, "");
00458     pal->optimal_resize();
00459     pal->generate_images(true);
00460     if (!pal->write_eggs()) {
00461       exit(1);
00462     }
00463     //    pal->report_pi();
00464   }
00465 }
00466 
00467 ////////////////////////////////////////////////////////////////////
00468 //     Function: EggMakeFont::dispatch_range
00469 //       Access: Private, Static
00470 //  Description: 
00471 ////////////////////////////////////////////////////////////////////
00472 bool EggMakeFont::
00473 dispatch_range(const string &, const string &arg, void *var) {
00474   RangeDescription *ip = (RangeDescription *)var;
00475   return ip->parse_parameter(arg);
00476 }
00477 
00478 ////////////////////////////////////////////////////////////////////
00479 //     Function: EggMakeFont::make_vertex
00480 //       Access: Private
00481 //  Description: Allocates and returns a new vertex from the vertex
00482 //               pool representing the indicated 2-d coordinates.
00483 ////////////////////////////////////////////////////////////////////
00484 EggVertex *EggMakeFont::
00485 make_vertex(const LPoint2d &xy) {
00486   return
00487     _vpool->make_new_vertex(LPoint3d::origin(_coordinate_system) +
00488                             LVector3d::rfu(xy[0], 0.0, xy[1], _coordinate_system));
00489 }
00490 
00491 ////////////////////////////////////////////////////////////////////
00492 //     Function: EggMakeFont::add_character
00493 //       Access: Private
00494 //  Description: Generates the indicated character and adds it to the
00495 //               font description.
00496 ////////////////////////////////////////////////////////////////////
00497 void EggMakeFont::
00498 add_character(int code) {
00499   PNMTextGlyph *glyph = _text_maker->get_glyph(code);
00500   if (glyph == (PNMTextGlyph *)NULL) {
00501     nout << "No definition in font for character " << code << ".\n";
00502     return;
00503   }
00504 
00505   make_geom(glyph, code);
00506 }
00507 
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: EggMakeFont::make_geom
00511 //       Access: Private
00512 //  Description: Creates the actual geometry for the glyph.
00513 ////////////////////////////////////////////////////////////////////
00514 void EggMakeFont::
00515 make_geom(PNMTextGlyph *glyph, int character) {
00516   // Create an egg group to hold the polygon.
00517   string group_name = format_string(character);
00518   EggGroup *group = new EggGroup(group_name);
00519   _group->add_child(group);
00520 
00521   if (glyph->get_width() != 0 && glyph->get_height() != 0) {
00522     int bitmap_top = glyph->get_top();
00523     int bitmap_left = glyph->get_left();
00524     double tex_x_size = glyph->get_width();
00525     double tex_y_size = glyph->get_height();
00526     
00527     double poly_margin = _poly_margin;
00528     double x_origin = _tex_margin;
00529     double y_origin = _tex_margin;
00530     double page_y_size = tex_y_size + _tex_margin * 2;
00531     double page_x_size = tex_x_size + _tex_margin * 2;
00532     
00533     // Determine the corners of the rectangle in geometric units.
00534     double tex_poly_margin = poly_margin / _pixels_per_unit;
00535     double origin_y = bitmap_top / _pixels_per_unit;
00536     double origin_x = bitmap_left / _pixels_per_unit;
00537     double top = origin_y + tex_poly_margin;
00538     double left = origin_x - tex_poly_margin;
00539     double bottom = origin_y - tex_y_size / _pixels_per_unit - tex_poly_margin;
00540     double right = origin_x + tex_x_size / _pixels_per_unit + tex_poly_margin;
00541     
00542     // And the corresponding corners in UV units.
00543     double uv_top = 1.0f - (double)(y_origin - poly_margin) / page_y_size;
00544     double uv_left = (double)(x_origin - poly_margin) / page_x_size;
00545     double uv_bottom = 1.0f - (double)(y_origin + poly_margin + tex_y_size) / page_y_size;
00546     double uv_right = (double)(x_origin + poly_margin + tex_x_size) / page_x_size;
00547     
00548     // Create the vertices for the polygon.
00549     EggVertex *v1 = make_vertex(LPoint2d(left, bottom));
00550     EggVertex *v2 = make_vertex(LPoint2d(right, bottom));
00551     EggVertex *v3 = make_vertex(LPoint2d(right, top));
00552     EggVertex *v4 = make_vertex(LPoint2d(left, top));
00553     
00554     v1->set_uv(LTexCoordd(uv_left, uv_bottom));
00555     v2->set_uv(LTexCoordd(uv_right, uv_bottom));
00556     v3->set_uv(LTexCoordd(uv_right, uv_top));
00557     v4->set_uv(LTexCoordd(uv_left, uv_top));
00558     
00559     EggPolygon *poly = new EggPolygon();
00560     group->add_child(poly);
00561     poly->set_texture(get_tref(glyph, character));
00562 
00563     poly->add_vertex(v1);
00564     poly->add_vertex(v2);
00565     poly->add_vertex(v3);
00566     poly->add_vertex(v4);
00567   }
00568 
00569   // Now create a single point where the origin of the next character
00570   // will be.
00571 
00572   EggVertex *v0 = make_vertex(LPoint2d(glyph->get_advance() / _pixels_per_unit + _render_margin, 0.0));
00573   EggPoint *point = new EggPoint;
00574   group->add_child(point);
00575   point->add_vertex(v0);
00576 }
00577 
00578 ////////////////////////////////////////////////////////////////////
00579 //     Function: EggMakeFont::get_tref
00580 //       Access: Private
00581 //  Description: Returns the egg texture reference for a particular
00582 //               glyph, creating it if it has not already been
00583 //               created.
00584 ////////////////////////////////////////////////////////////////////
00585 EggTexture *EggMakeFont::
00586 get_tref(PNMTextGlyph *glyph, int character) {
00587   TRefs::iterator ti = _trefs.find(glyph);
00588   if (ti != _trefs.end()) {
00589     return (*ti).second;
00590   }
00591 
00592   EggTexture *tref = make_tref(glyph, character);
00593   _trefs[glyph] = tref;
00594   return tref;
00595 }
00596 
00597 ////////////////////////////////////////////////////////////////////
00598 //     Function: EggMakeFont::make_tref
00599 //       Access: Private
00600 //  Description: Generates a texture image for the indicated glyph,
00601 //               and returns its egg reference.
00602 ////////////////////////////////////////////////////////////////////
00603 EggTexture *EggMakeFont::
00604 make_tref(PNMTextGlyph *glyph, int character) {
00605   char buffer[1024];
00606   sprintf(buffer, _output_glyph_pattern.c_str(), character);
00607 
00608   Filename texture_filename = buffer;
00609   PNMImage image(glyph->get_width() + _tex_margin * 2,
00610                  glyph->get_height() + _tex_margin * 2, _num_channels);
00611   image.fill(_bg[0], _bg[1], _bg[2]);
00612   if (image.has_alpha()) {
00613     image.alpha_fill(_bg[3]);
00614   }
00615   if (_got_interior) {
00616     glyph->place(image, -glyph->get_left() + _tex_margin, 
00617                  glyph->get_top() + _tex_margin, _fg, _interior);
00618   } else {
00619     glyph->place(image, -glyph->get_left() + _tex_margin, 
00620                  glyph->get_top() + _tex_margin, _fg);
00621   }
00622 
00623   // We don't write the image to disk immediately, since it might just
00624   // get palettized.  But we do record it in a TextureImage object
00625   // within the global Palettizer, so that it may be written out
00626   // later.
00627 
00628   string name = texture_filename.get_basename_wo_extension();
00629   TextureImage *texture = pal->get_texture(name);
00630   _textures.push_back(texture);
00631   texture->set_filename("", texture_filename);
00632   SourceTextureImage *source = texture->get_source(texture_filename, "", 0);
00633   texture->set_source_image(image);
00634   source->set_header(image);
00635 
00636   EggTexture *tref = new EggTexture(name, texture_filename);
00637   tref->set_format(_format);
00638   tref->set_wrap_mode(EggTexture::WM_clamp);
00639   tref->set_minfilter(EggTexture::FT_linear_mipmap_linear);
00640   tref->set_magfilter(EggTexture::FT_linear);
00641   tref->set_quality_level(EggTexture::QL_best);
00642 
00643   return tref;
00644 }
00645 
00646 ////////////////////////////////////////////////////////////////////
00647 //     Function: EggMakeFont::add_extra_glyphs
00648 //       Access: Private
00649 //  Description: Reads the indicated filename and adds any numbered
00650 //               groups into the current egg file.
00651 ////////////////////////////////////////////////////////////////////
00652 void EggMakeFont::
00653 add_extra_glyphs(const Filename &extra_filename) {
00654   PT(EggData) extra_data = new EggData;
00655 
00656   if (!extra_data->read(extra_filename)) {
00657     return;
00658   }
00659 
00660   _group->steal_children(*extra_data);
00661 }
00662 
00663 ////////////////////////////////////////////////////////////////////
00664 //     Function: EggMakeFont::r_add_extra_glyphs
00665 //       Access: Private
00666 //  Description: Recursively searches for numbered groups in the
00667 //               indicated egg file, and copies them to the current
00668 //               egg file.
00669 ////////////////////////////////////////////////////////////////////
00670 void EggMakeFont::
00671 r_add_extra_glyphs(EggGroupNode *egg_group) {
00672   if (egg_group->is_of_type(EggGroup::get_class_type())) {
00673     EggGroup *group = DCAST(EggGroup, egg_group);
00674     if (is_numeric(group->get_name())) {
00675       EggGroup *new_group = new EggGroup(group->get_name());
00676       _group->add_child(new_group);
00677       new_group->steal_children(*group);
00678       return;
00679     }
00680   }
00681 
00682   EggGroupNode::iterator ci;
00683   for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00684     EggNode *child = (*ci);
00685     if (child->is_of_type(EggGroupNode::get_class_type())) {
00686       r_add_extra_glyphs(DCAST(EggGroupNode, child));
00687     }
00688   }
00689 }
00690 
00691 ////////////////////////////////////////////////////////////////////
00692 //     Function: EggMakeFont::is_numeric
00693 //       Access: Private, Static
00694 //  Description: Returns true if the indicated string is all numeric
00695 //               digits, false otherwise.
00696 ////////////////////////////////////////////////////////////////////
00697 bool EggMakeFont::
00698 is_numeric(const string &str) {
00699   if (str.empty()) {
00700     return false;
00701   }
00702 
00703   string::const_iterator si;
00704   for (si = str.begin(); si != str.end(); ++si) {
00705     if (!isdigit(*si)) {
00706       return false;
00707     }
00708   }
00709 
00710   return true;
00711 }
00712 
00713 int main(int argc, char *argv[]) {
00714   // A call to pystub() to force libpystub.so to be linked in.
00715   pystub();
00716 
00717   EggMakeFont prog;
00718   prog.parse_command_line(argc, argv);
00719   prog.run();
00720   return 0;
00721 }
 All Classes Functions Variables Enumerations