Panda3D
|
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 }