42 set_program_brief(
"generates .egg files with rasterized font glyphs");
43 set_program_description
44 (
"egg-mkfont uses the FreeType library to generate an egg file "
45 "and a series of texture images from a font file "
46 "input, such as a TTF file. The resulting egg file "
47 "can be loaded in Panda as a font for rendering text, even "
48 "if FreeType is not compiled into the executing Panda.\n\n"
50 "egg-mkfont will normally run the generated egg file through "
51 "egg-palettize automatically as part of the generation process. "
52 "This collects the individual glyph textures into a small number "
53 "of texture maps. If you intend to run the font through egg-palettize "
54 "yourself later, you may choose to omit this step.");
57 add_runline(
"[opts] -o output.egg font");
58 add_runline(
"[opts] font output.egg");
61 (
"fg",
"r,g,b[,a]", 0,
62 "Specifies the foreground color of the generated texture map. The "
63 "default is white: 1,1,1,1, which leads to the most flexibility "
64 "as the color can be modulated at runtime to any suitable color.",
65 &EggMakeFont::dispatch_color,
nullptr, &_fg[0]);
68 (
"bg",
"r,g,b[,a]", 0,
69 "Specifies the background color of the generated texture map. The "
70 "default is transparent: 1,1,1,0, which allows the text to be "
71 "visible against any color background by placing a polygon of a "
72 "suitable color behind it. If the alpha component of either -fg "
73 "or -bg is not 1, the generated texture images will include an "
74 "alpha component; if both colors specify an alpha component of 1 "
75 "(or do not specify an alpha compenent), then the generated images "
76 "will not include an alpha component.",
77 &EggMakeFont::dispatch_color,
nullptr, &_bg[0]);
80 (
"interior",
"r,g,b[,a]", 0,
81 "Specifies the color to render the interior part of a hollow font. "
82 "This is a special effect that involves analysis of the bitmap after "
83 "the font has been rendered, and so is more effective when the pixel "
84 "size is large. It also implies -noaa (but you can use a scale "
85 "factor with -sf to achieve antialiasing).",
86 &EggMakeFont::dispatch_color, &_got_interior, &_interior[0]);
90 "Specifies the characters of the font that are used. The range "
91 "specification may include combinations of decimal or hex unicode "
92 "values (where hex values are identified with a leading 0x), separated "
93 "by commas and hyphens to indicate ranges, e.g. '32-126,0xfa0-0xfff'. "
94 "It also may specify ranges of ASCII characters by enclosing them "
95 "within square brackets, e.g. '[A-Za-z0-9]'. If this is not specified, "
96 "the default set has all ASCII characters and an assorted set of "
97 "latin-1 characters, diacritics and punctuation marks.",
98 &EggMakeFont::dispatch_range,
nullptr, &_range);
101 (
"extra",
"file.egg", 0,
102 "Specifies additional externally-painted glyphs to mix into the "
103 "generated egg file. The named egg file is expected to contain one "
104 "or more groups, each of which is named with the decimal unicode "
105 "number of a character and should contain one polygon. These groups "
106 "are simply copied into the output egg file as if they were generated "
107 "locally. This option may be repeated.",
108 &EggMakeFont::dispatch_vector_string,
nullptr, &_extra_filenames);
112 "Specify the pixels per unit. This is the number of pixels in the "
113 "generated texture map that are used for each onscreen unit (or each "
114 "10 points of font; see -ps). Setting this number larger results in "
115 "an easier-to-read font, but at the cost of more texture memory. "
116 "The default is 40.",
117 &EggMakeFont::dispatch_double,
nullptr, &_pixels_per_unit);
121 "Specify the point size of the resulting font. This controls the "
122 "apparent size of the font when it is rendered onscreen. By convention, "
123 "a 10 point font is 1 screen unit high, so the default is 10.",
124 &EggMakeFont::dispatch_double,
nullptr, &_point_size);
128 "If this is set, a signed distance field will be generated, which "
129 "results in crisp text even when the text is enlarged or zoomed in.",
130 &EggMakeFont::dispatch_true,
nullptr, &_generate_distance_field);
134 "The number of extra pixels around a single character in the "
135 "generated polygon. This may be a floating-point number. The "
137 &EggMakeFont::dispatch_double,
nullptr, &_poly_margin);
141 "The number of extra pixels around each character in the texture map. "
142 "This may only be an integer. The default is 2. This is meaningful "
143 "when -nopal is also used; in the normal case, use -pm to control "
144 "both the polygon size and the texture map spacing.",
145 &EggMakeFont::dispatch_int,
nullptr, &_tex_margin);
149 "The amount of padding in screen units to place around the glyph when "
150 "rendered. This differs from -pm in that it has no effect on the "
151 "generated texture map, only on the generated egg. Use this in order to "
152 "space the characters out in case they appear to be too close together "
153 "when rendered. The default is 0.",
154 &EggMakeFont::dispatch_double,
nullptr, &_render_margin);
158 "The scale factor of the generated image. This is the factor by which "
159 "the font image is generated oversized, then reduced to its final size, "
160 "to improve antialiasing. If the specified font contains one "
161 "or more fixed-size fonts instead of a scalable font, the scale factor "
162 "may be automatically adjusted as necessary to scale the closest-"
163 "matching font to the desired pixel size. The default is 2.",
164 &EggMakeFont::dispatch_double, &_got_scale_factor, &_scale_factor);
168 "Disable low-level antialiasing by the Freetype library. "
169 "This is unrelated to the antialiasing that is applied due to the "
170 "scale factor specified by -sf; you may have either one, neither, or "
171 "both kinds of antialiasing enabled.",
172 &EggMakeFont::dispatch_none, &_no_native_aa);
176 "Don't run egg-palettize automatically on the output file, but "
177 "just output the raw egg file and all of its individual texture "
178 "images, one for each glyph.",
179 &EggMakeFont::dispatch_none, &_no_palettize);
183 "Don't actually reduce the images after applying the scale factor, but "
184 "leave them at their inflated sizes. Presumably you will reduce "
185 "them later, for instance with egg-palettize.",
186 &EggMakeFont::dispatch_none, &_no_reduce);
190 "The pattern to be used to generate the glyph texture images. This "
191 "string will be passed to sprintf to generate the actual file name; it "
192 "should contain the string %d or %x (or some variant such as %03d) "
193 "which will be filled in with the Unicode number of each symbol. "
194 "If it is omitted, the default is based on the name of the egg file. "
195 "This is used only if -nopal is specified; in the normal case, "
196 "without -nopal, use -pp instead.",
197 &EggMakeFont::dispatch_string,
nullptr, &_output_glyph_pattern);
201 "The pattern to be used to generate the palette texture images. This "
202 "string is effectively passed to egg-palettize as the -tn option, and "
203 "thus should contain %i for the palette index number. This is used "
204 "if -nopal is not specified.",
205 &EggMakeFont::dispatch_string,
nullptr, &_output_palette_pattern);
208 (
"palsize",
"xsize,ysize", 0,
209 "Specify the size of the palette texture images. This is used if "
210 "-nopal is not specified.",
211 &EggMakeFont::dispatch_int_pair,
nullptr, _palette_size);
215 "Specify the face index of the particular face within the font file "
216 "to use. Some font files contain multiple faces, indexed beginning "
217 "at 0. The default is face 0.",
218 &EggMakeFont::dispatch_int,
nullptr, &_face_index);
220 _fg.set(1.0, 1.0, 1.0, 1.0);
221 _bg.set(1.0, 1.0, 1.0, 0.0);
222 _interior.set(1.0, 1.0, 1.0, 1.0);
223 _pixels_per_unit = 40.0;
227 _render_margin = 0.0;
228 _palette_size[0] = _palette_size[1] = 512;
230 _generate_distance_field =
false;
232 _text_maker =
nullptr;
246 nout <<
"Must specify name of font file on command line.\n";
250 _input_font_filename = args[0];
252 return EggWriter::handle_args(args);
266 _text_maker =
new PNMTextMaker(_input_font_filename, _face_index);
272 _no_native_aa =
true;
275 if (!_got_scale_factor) {
278 if (_generate_distance_field) {
280 }
else if (_no_native_aa) {
287 _text_maker->set_point_size(_point_size);
288 _text_maker->set_native_antialias(!_no_native_aa);
290 _text_maker->set_pixels_per_unit(_pixels_per_unit);
291 _text_maker->set_scale_factor(_scale_factor);
295 _pixels_per_unit = _text_maker->get_pixels_per_unit();
296 _scale_factor = _text_maker->get_scale_factor();
298 if (_text_maker->get_font_pixel_size() != 0) {
299 nout <<
"Using " << _text_maker->get_font_pixel_size() <<
"-pixel font.\n";
305 _palettize_scale_factor = _scale_factor;
306 if (_scale_factor != 1.0 && (_no_reduce || !_no_palettize)) {
314 _tex_margin = (int)(_tex_margin * _scale_factor);
315 _poly_margin *= _scale_factor;
316 _pixels_per_unit *= _scale_factor;
318 _text_maker->set_pixels_per_unit(_pixels_per_unit);
319 _text_maker->set_scale_factor(1.0);
326 _palette_size[0] = (int)(_palette_size[0] * _palettize_scale_factor);
327 _palette_size[1] = (int)(_palette_size[1] * _palettize_scale_factor);
328 _palettize_scale_factor = 1.0;
333 _range.add_range(0x20, 0x7e);
335 _range.add_singleton(0xa1);
336 _range.add_singleton(0xa9);
337 _range.add_singleton(0xab);
339 _range.add_singleton(0xb0);
340 _range.add_singleton(0xb5);
341 _range.add_singleton(0xb8);
342 _range.add_singleton(0xbb);
343 _range.add_singleton(0xbf);
345 _range.add_singleton(0xc6);
346 _range.add_singleton(0xc7);
349 _range.add_singleton(0xdf);
350 _range.add_singleton(0xe6);
351 _range.add_singleton(0xe7);
352 _range.add_singleton(0xf0);
353 _range.add_singleton(0xf8);
354 _range.add_singleton(0xfe);
359 _range.add_singleton(0x0131);
360 _range.add_singleton(0x0237);
363 _range.add_range(0x2018, 0x201f);
365 _range.add_singleton(0x2026);
368 _range.add_range(0x0300, 0x030f);
370 if (_output_glyph_pattern.empty()) {
374 if (_output_palette_pattern.empty()) {
381 bool needs_alpha = (_fg[3] != 1.0 || _bg[3] != 1.0 || _interior[3] != 1.0);
382 bool needs_color = (_fg[0] != _fg[1] || _fg[1] != _fg[2] ||
383 _bg[0] != _bg[1] || _bg[1] != _bg[2] ||
384 _interior[0] != _interior[1] || _interior[1] != _interior[2]);
389 _format = EggTexture::F_rgba;
391 if (_fg[0] == 1.0 && _bg[0] == 1.0 && _interior[0] == 1.0) {
394 _fg[0] = _fg[1] = _fg[2] = _fg[3];
395 _bg[0] = _bg[1] = _bg[2] = _bg[3];
396 _interior[0] = _interior[1] = _interior[2] = _interior[3];
398 _format = EggTexture::F_alpha;
401 _format = EggTexture::F_luminance_alpha;
407 _format = EggTexture::F_rgb;
410 _format = EggTexture::F_luminance;
418 pal->_generated_image_pattern = _output_palette_pattern;
419 pal->_omit_solitary =
false;
420 pal->_round_uvs =
false;
425 sprintf(buffer,
":margin 0;:coverage 1000;:background %f %f %f %f;:palette %d %d;*: %f%% keep-format",
426 _bg[0], _bg[1], _bg[2], _bg[3],
427 _palette_size[0], _palette_size[1],
428 100.0 / _palettize_scale_factor);
429 std::istringstream txa_script(buffer);
439 egg_data->add_child(_group);
440 append_command_comment(egg_data);
447 _group->set_switch_flag(
true);
448 _group->set_switch_fps(2.0);
450 double margin = _poly_margin;
451 if (_generate_distance_field) {
456 if (_poly_margin >= 1) {
468 EggVertex *vtx = make_vertex(LPoint2d(margin / _pixels_per_unit, _text_maker->get_line_height()));
476 add_character(ri.get_code());
480 if (!_extra_filenames.empty()) {
481 vector_string::const_iterator si;
482 for (si = _extra_filenames.begin(); si != _extra_filenames.end(); ++si) {
483 add_extra_glyphs(*si);
490 Textures::iterator ti;
491 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
521 dispatch_range(
const string &,
const string &arg,
void *var) {
531 make_vertex(
const LPoint2d &xy) {
534 LVector3d::rfu(xy[0], 0.0, xy[1], _coordinate_system));
541 add_character(
int code) {
543 if (glyph ==
nullptr) {
544 nout <<
"No definition in font for character " << code <<
".\n";
548 make_geom(glyph, code);
558 string group_name = format_string(character);
563 int bitmap_top = glyph->
get_top();
564 int bitmap_left = glyph->
get_left();
568 double poly_margin = _poly_margin;
569 double x_origin = _tex_margin;
570 double y_origin = _tex_margin;
571 double page_y_size = tex_y_size + _tex_margin * 2;
572 double page_x_size = tex_x_size + _tex_margin * 2;
575 double tex_poly_margin = poly_margin / _pixels_per_unit;
576 double origin_y = bitmap_top / _pixels_per_unit;
577 double origin_x = bitmap_left / _pixels_per_unit;
578 double top = origin_y + tex_poly_margin;
579 double left = origin_x - tex_poly_margin;
580 double bottom = origin_y - tex_y_size / _pixels_per_unit - tex_poly_margin;
581 double right = origin_x + tex_x_size / _pixels_per_unit + tex_poly_margin;
584 double uv_top = 1.0f - (double)(y_origin - poly_margin) / page_y_size;
585 double uv_left = (double)(x_origin - poly_margin) / page_x_size;
586 double uv_bottom = 1.0f - (double)(y_origin + poly_margin + tex_y_size) / page_y_size;
587 double uv_right = (double)(x_origin + poly_margin + tex_x_size) / page_x_size;
590 EggVertex *v1 = make_vertex(LPoint2d(left, bottom));
591 EggVertex *v2 = make_vertex(LPoint2d(right, bottom));
592 EggVertex *v3 = make_vertex(LPoint2d(right, top));
593 EggVertex *v4 = make_vertex(LPoint2d(left, top));
595 v1->
set_uv(LTexCoordd(uv_left, uv_bottom));
596 v2->
set_uv(LTexCoordd(uv_right, uv_bottom));
597 v3->
set_uv(LTexCoordd(uv_right, uv_top));
598 v4->
set_uv(LTexCoordd(uv_left, uv_top));
612 EggVertex *v0 = make_vertex(LPoint2d(glyph->
get_advance() / _pixels_per_unit + _render_margin, 0.0));
624 TRefs::iterator ti = _trefs.find(glyph);
625 if (ti != _trefs.end()) {
629 EggTexture *tref = make_tref(glyph, character);
630 _trefs[glyph] = tref;
641 sprintf(buffer, _output_glyph_pattern.c_str(), character);
645 glyph->
get_height() + _tex_margin * 2, _num_channels);
646 image.fill(_bg[0], _bg[1], _bg[2]);
647 if (image.has_alpha()) {
648 image.alpha_fill(_bg[3]);
652 glyph->
get_top() + _tex_margin, _fg, _interior);
655 glyph->
get_top() + _tex_margin, _fg);
664 _textures.push_back(texture);
671 tref->set_format(_format);
672 tref->set_wrap_mode(EggTexture::WM_clamp);
673 tref->set_minfilter(EggTexture::FT_linear_mipmap_linear);
674 tref->set_magfilter(EggTexture::FT_linear);
675 tref->set_quality_level(EggTexture::QL_best);
685 add_extra_glyphs(
const Filename &extra_filename) {
688 if (!extra_data->read(extra_filename)) {
701 if (egg_group->
is_of_type(EggGroup::get_class_type())) {
703 if (is_numeric(group->get_name())) {
711 EggGroupNode::iterator ci;
712 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
714 if (child->
is_of_type(EggGroupNode::get_class_type())) {
725 is_numeric(
const string &str) {
730 string::const_iterator si;
731 for (si = str.begin(); si != str.end(); ++si) {
740 int main(
int argc,
char *argv[]) {