15 #include "eggMakeFont.h"
16 #include "rangeIterator.h"
17 #include "palettizer.h"
18 #include "filenameUnifier.h"
20 #include "textureImage.h"
21 #include "sourceTextureImage.h"
22 #include "pnmTextMaker.h"
23 #include "pnmTextGlyph.h"
27 #include "eggPolygon.h"
28 #include "eggTexture.h"
29 #include "eggVertexPool.h"
30 #include "eggVertex.h"
31 #include "string_utils.h"
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"
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.");
59 add_runline(
"[opts] -o output.egg font");
60 add_runline(
"[opts] font output.egg");
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]);
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]);
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]);
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);
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);
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);
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);
129 "The number of extra pixels around a single character in the "
130 "generated polygon. This may be a floating-point number. The "
132 &EggMakeFont::dispatch_double, NULL, &_poly_margin);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
222 _render_margin = 0.0;
223 _palette_size[0] = _palette_size[1] = 256;
243 nout <<
"Must specify name of font file on command line.\n";
247 _input_font_filename = args[0];
249 return EggWriter::handle_args(args);
265 _text_maker =
new PNMTextMaker(_input_font_filename, _face_index);
271 _no_native_aa =
true;
274 if (!_got_scale_factor) {
284 _text_maker->set_point_size(_point_size);
285 _text_maker->set_native_antialias(!_no_native_aa);
287 _text_maker->set_pixels_per_unit(_pixels_per_unit);
288 _text_maker->set_scale_factor(_scale_factor);
292 _pixels_per_unit = _text_maker->get_pixels_per_unit();
293 _scale_factor = _text_maker->get_scale_factor();
295 if (_text_maker->get_font_pixel_size() != 0) {
296 nout <<
"Using " << _text_maker->get_font_pixel_size() <<
"-pixel font.\n";
303 _palettize_scale_factor = _scale_factor;
304 if (_scale_factor != 1.0 && (_no_reduce || !_no_palettize)) {
312 _tex_margin = (int)(_tex_margin * _scale_factor);
313 _poly_margin *= _scale_factor;
314 _pixels_per_unit *= _scale_factor;
316 _text_maker->set_pixels_per_unit(_pixels_per_unit);
317 _text_maker->set_scale_factor(1.0);
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;
332 _range.add_range(0x20, 0x7e);
334 if (_output_glyph_pattern.empty()) {
338 if (_output_palette_pattern.empty()) {
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]);
353 _format = EggTexture::F_rgba;
355 if (_fg[0] == 1.0 && _bg[0] == 1.0 && _interior[0] == 1.0) {
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];
363 _format = EggTexture::F_alpha;
366 _format = EggTexture::F_luminance_alpha;
372 _format = EggTexture::F_rgb;
375 _format = EggTexture::F_luminance;
383 pal->_generated_image_pattern = _output_palette_pattern;
384 pal->_omit_solitary =
false;
385 pal->_round_uvs =
false;
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);
405 egg_data->add_child(_group);
406 append_command_comment(egg_data);
409 _group->add_child(_vpool);
413 _group->set_switch_flag(true);
414 _group->set_switch_fps(2.0);
417 EggGroup *ds_group = new EggGroup("ds");
418 _group->add_child(ds_group);
421 ds_group->add_child(point);
422 point->add_vertex(vtx);
427 add_character(ri.get_code());
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);
441 Textures::iterator ti;
442 for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
474 dispatch_range(
const string &,
const string &arg,
void *var) {
486 make_vertex(
const LPoint2d &xy) {
499 add_character(
int code) {
502 nout <<
"No definition in font for character " << code <<
".\n";
506 make_geom(glyph, code);
518 string group_name = format_string(character);
519 EggGroup *group =
new EggGroup(group_name);
520 _group->add_child(group);
523 int bitmap_top = glyph->
get_top();
524 int bitmap_left = glyph->
get_left();
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;
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;
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;
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));
573 EggVertex *v0 = make_vertex(LPoint2d(glyph->
get_advance() / _pixels_per_unit + _render_margin, 0.0));
574 EggPoint *point =
new EggPoint;
576 point->add_vertex(v0);
588 TRefs::iterator ti = _trefs.find(glyph);
589 if (ti != _trefs.end()) {
593 EggTexture *tref = make_tref(glyph, character);
594 _trefs[glyph] = tref;
607 sprintf(buffer, _output_glyph_pattern.c_str(), character);
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]);
618 glyph->
get_top() + _tex_margin, _fg, _interior);
621 glyph->
get_top() + _tex_margin, _fg);
629 string name = texture_filename.get_basename_wo_extension();
631 _textures.push_back(texture);
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);
654 add_extra_glyphs(
const Filename &extra_filename) {
655 PT(EggData) extra_data = new EggData;
657 if (!extra_data->read(extra_filename)) {
661 _group->steal_children(*extra_data);
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);
683 EggGroupNode::iterator ci;
684 for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
686 if (child->
is_of_type(EggGroupNode::get_class_type())) {
699 is_numeric(
const string &str) {
704 string::const_iterator si;
705 for (si = str.begin(); si != str.end(); ++si) {
714 int main(
int argc,
char *argv[]) {
string get_fullpath_wo_extension() const
Returns the full filename–directory and basename parts–except for the extension.
int get_top() const
Returns the y coordinate of the topmost pixel in the glyph.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
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.
bool set_filename(PaletteGroup *group, const string &basename)
Sets the filename, and if applicable, the alpha_filename, from the indicated basename.
A base class for nodes in the hierarchy that are not leaf nodes.
int get_height() const
Returns the height of the glyph in pixels.
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.
void process_all(bool force_texture_read, const Filename &state_filename)
Reprocesses all textures known.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
void set_texture(EggTexture *texture)
Replaces the current list of textures with the indicated texture.
EggFile * get_egg_file(const string &name)
Returns the EggFile with the given name.
This is a two-component point in space.
Walks through all the Unicode characters described by a RangeDescription class.
This program uses FreeType to generate an egg file and a series of texture images from a font file in...
This is the primary interface into all the egg data, and the root of the egg file structure...
This object uses the Freetype library to generate text directly into an image.
A single point, or a collection of points as defined by a single <PointLight> entry.
int get_width() const
Returns the width of the glyph in pixels.
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
bool parse_parameter(const string ¶m)
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.
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.
int get_left() const
Returns the x coordinate of the leftmost pixel in the glyph.
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
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...
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
static const LPoint3d & origin(CoordinateSystem cs=CS_default)
Returns the origin of the indicated coordinate system.
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.
void all_params_set()
Called after all command line parameters have been set up, this is a hook to do whatever initializati...
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
int get_advance() const
Returns the number of pixels by which the pen should be advanced after rendering this glyph...
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
bool is_valid() const
Returns true if the PNMTextMaker is valid and ready to generate text, false otherwise.
bool is_empty() const
Returns true if there are no codes described in the range.
bool write_eggs()
Adjusts the egg files to reference the newly generated textures, and writes them out.
void set_header(const PNMImageHeader &header)
Sets the header information associated with this image, as if it were loaded from the disk...
bool write(const PNMImage &image) const
Writes out the image in the indicated PNMImage to the _filename and/or _alpha_filename.
void generate_images(bool redo_all)
Actually generates the appropriate palette and unplaced texture images into the map directories...
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.
void set_interior_flag(bool interior_flag)
Sets the flag that indicates whether the interior of hollow fonts is identified as a preprocess as ea...
ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout...
string get_basename() const
Returns the basename part of the filename.
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.
string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
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.
A single glyph in a PNMTextMaker.
This is the base class for a program that generates an egg file output, but doesn't read any for inpu...
This represents a single source texture that is referenced by one or more egg files.
void optimal_resize()
Attempts to resize each PalettteImage down to its smallest possible size.
void fill(float red, float green, float blue)
Sets the entire image (except the alpha channel) to the given color.
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...
TextureImage * get_texture(const string &name)
Returns the TextureImage with the given name.
void set_uv(const LTexCoordd &texCoord)
Replaces the unnamed UV coordinate pair on the vertex with the indicated value.
A collection of vertices.
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive'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.
PNMTextGlyph * get_glyph(int character)
Returns the glyph for the indicated index, or NULL if it is not defined in the font.
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.