From abb0c97f85fbb78b69e27d47e8de8c2aed274f72 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 9 Sep 2003 19:30:38 +0000 Subject: [PATCH] new egg-mkfont --- pandatool/src/egg-mkfont/Sources.pp | 26 +- pandatool/src/egg-mkfont/T1-WGL4.enc | 128 --- pandatool/src/egg-mkfont/charBitmap.cxx | 76 -- pandatool/src/egg-mkfont/charBitmap.h | 56 - pandatool/src/egg-mkfont/charLayout.cxx | 127 --- pandatool/src/egg-mkfont/charLayout.h | 55 - pandatool/src/egg-mkfont/charPlacement.cxx | 41 - pandatool/src/egg-mkfont/charPlacement.h | 48 - .../src/egg-mkfont/egg-mkfont_composite1.cxx | 5 - pandatool/src/egg-mkfont/eggMakeFont.cxx | 1003 +++++------------ pandatool/src/egg-mkfont/eggMakeFont.h | 95 +- pandatool/src/egg-mkfont/fontFile.I | 91 -- pandatool/src/egg-mkfont/fontFile.cxx | 67 -- pandatool/src/egg-mkfont/fontFile.h | 65 -- pandatool/src/egg-mkfont/pfb2egg | 164 --- pandatool/src/egg-mkfont/pkFontFile.cxx | 916 --------------- pandatool/src/egg-mkfont/pkFontFile.h | 64 -- pandatool/src/egg-mkfont/rangeDescription.I | 78 ++ pandatool/src/egg-mkfont/rangeDescription.cxx | 199 ++++ pandatool/src/egg-mkfont/rangeDescription.h | 68 ++ .../{charBitmap.I => rangeIterator.I} | 26 +- pandatool/src/egg-mkfont/rangeIterator.cxx | 74 ++ .../{charPlacement.I => rangeIterator.h} | 48 +- pandatool/src/egg-mkfont/ttf2egg | 134 --- pandatool/src/progbase/programBase.cxx | 30 +- 25 files changed, 831 insertions(+), 2853 deletions(-) delete mode 100644 pandatool/src/egg-mkfont/T1-WGL4.enc delete mode 100644 pandatool/src/egg-mkfont/charBitmap.cxx delete mode 100644 pandatool/src/egg-mkfont/charBitmap.h delete mode 100644 pandatool/src/egg-mkfont/charLayout.cxx delete mode 100644 pandatool/src/egg-mkfont/charLayout.h delete mode 100644 pandatool/src/egg-mkfont/charPlacement.cxx delete mode 100644 pandatool/src/egg-mkfont/charPlacement.h delete mode 100644 pandatool/src/egg-mkfont/fontFile.I delete mode 100644 pandatool/src/egg-mkfont/fontFile.cxx delete mode 100644 pandatool/src/egg-mkfont/fontFile.h delete mode 100644 pandatool/src/egg-mkfont/pfb2egg delete mode 100644 pandatool/src/egg-mkfont/pkFontFile.cxx delete mode 100644 pandatool/src/egg-mkfont/pkFontFile.h create mode 100644 pandatool/src/egg-mkfont/rangeDescription.I create mode 100644 pandatool/src/egg-mkfont/rangeDescription.cxx create mode 100644 pandatool/src/egg-mkfont/rangeDescription.h rename pandatool/src/egg-mkfont/{charBitmap.I => rangeIterator.I} (63%) create mode 100644 pandatool/src/egg-mkfont/rangeIterator.cxx rename pandatool/src/egg-mkfont/{charPlacement.I => rangeIterator.h} (51%) delete mode 100755 pandatool/src/egg-mkfont/ttf2egg diff --git a/pandatool/src/egg-mkfont/Sources.pp b/pandatool/src/egg-mkfont/Sources.pp index 4ca245cf0d..2d21898163 100644 --- a/pandatool/src/egg-mkfont/Sources.pp +++ b/pandatool/src/egg-mkfont/Sources.pp @@ -1,3 +1,7 @@ +#define BUILD_DIRECTORY $[HAVE_FREETYPE] + +#define USE_PACKAGES freetype + #define LOCAL_LIBS \ eggbase progbase #define OTHER_LIBS \ @@ -5,24 +9,20 @@ egg:c linmath:c putil:c express:c pandaegg:m panda:m pandaexpress:m \ dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub -#define UNIX_SYS_LIBS m - #begin bin_target #define TARGET egg-mkfont - #define COMBINED_SOURCES $[TARGET]_composite1.cxx +// #define COMBINED_SOURCES $[TARGET]_composite1.cxx - #define SOURCES \ - charBitmap.I charBitmap.h \ - charLayout.h eggMakeFont.h \ - fontFile.I fontFile.h pkFontFile.h + #defer SOURCES \ + eggMakeFont.h \ + rangeDescription.h rangeDescription.I \ + rangeIterator.h rangeIterator.I \ + $[INCLUDED_SOURCES] #define INCLUDED_SOURCES \ - charBitmap.cxx charLayout.cxx \ - charPlacement.cxx eggMakeFont.cxx \ - fontFile.cxx pkFontFile.cxx \ + eggMakeFont.cxx \ + rangeDescription.cxx \ + rangeIterator.cxx #end bin_target - -#define INSTALL_SCRIPTS ttf2egg pfb2egg -#define INSTALL_DATA T1-WGL4.enc diff --git a/pandatool/src/egg-mkfont/T1-WGL4.enc b/pandatool/src/egg-mkfont/T1-WGL4.enc deleted file mode 100644 index 064c723a8f..0000000000 --- a/pandatool/src/egg-mkfont/T1-WGL4.enc +++ /dev/null @@ -1,128 +0,0 @@ -% T1-WGL4.enc -% -% -% This is LaTeX T1 encoding for WGL4 encoded TrueType fonts -% (e.g. from Windows 95) -% -% -% Note that /hyphen appears twice (for the T1 code points `hyphen' 0x2d -% and `hyphenchar' 0x7f). -% -% -% LIGKERN space l =: lslash ; -% LIGKERN space L =: Lslash ; -% LIGKERN question quoteleft =: questiondown ; -% LIGKERN exclam quoteleft =: exclamdown ; -% LIGKERN hyphen hyphen =: endash ; -% LIGKERN endash hyphen =: emdash ; -% LIGKERN quoteleft quoteleft =: quotedblleft ; -% LIGKERN quoteright quoteright =: quotedblright ; -% LIGKERN comma comma =: quotedblbase ; -% LIGKERN less less =: guillemotleft ; -% LIGKERN greater greater =: guillemotright ; -% -% LIGKERN f i =: fi ; -% LIGKERN f l =: fl ; -% LIGKERN f f =: ff ; -% LIGKERN ff i =: ffi ; -% LIGKERN ff l =: ffl ; -% -% We blow away kerns to and from spaces (TeX doesn't have a -% space) and also remove any kerns from the numbers. -% -% LIGKERN space {} * ; * {} space ; -% LIGKERN zero {} * ; * {} zero ; -% LIGKERN one {} * ; * {} one ; -% LIGKERN two {} * ; * {} two ; -% LIGKERN three {} * ; * {} three ; -% LIGKERN four {} * ; * {} four ; -% LIGKERN five {} * ; * {} five ; -% LIGKERN six {} * ; * {} six ; -% LIGKERN seven {} * ; * {} seven ; -% LIGKERN eight {} * ; * {} eight ; -% LIGKERN nine {} * ; * {} nine ; - -/T1Encoding [ % now 256 chars follow -% 0x00 - /grave /acute /circumflex /tilde - /dieresis /hungarumlaut /ring /caron - /breve /macron /dotaccent /cedilla - /ogonek /quotesinglbase /guilsinglleft /guilsinglright -% 0x10 - /quotedblleft /quotedblright /quotedblbase /guillemotleft - /guillemotright /endash /emdash /compwordmark - /perthousandzero /dotlessi /dotlessj /ff - /fi /fl /ffi /ffl -% 0x20 - /visualspace /exclam /quotedbl /numbersign - /dollar /percent /ampersand /quoteright - /parenleft /parenright /asterisk /plus - /comma /hyphen /period /slash -% 0x30 - /zero /one /two /three - /four /five /six /seven - /eight /nine /colon /semicolon - /less /equal /greater /question -% 0x40 - /at /A /B /C - /D /E /F /G - /H /I /J /K - /L /M /N /O -% 0x50 - /P /Q /R /S - /T /U /V /W - /X /Y /Z /bracketleft - /backslash /bracketright /asciicircum /underscore -% 0x60 - /quoteleft /a /b /c - /d /e /f /g - /h /i /j /k - /l /m /n /o -% 0x70 - /p /q /r /s - /t /u /v /w - /x /y /z /braceleft - /bar /braceright /asciitilde /hyphen -% 0x80 - /Abreve /Aogonek /Cacute /Ccaron - /Dcaron /Ecaron /Eogonek /Gbreve - /Lacute /Lcaron /Lslash /Nacute - /Ncaron /Eng /Odblacute /Racute -% 0x90 - /Rcaron /Sacute /Scaron /Scedilla - /Tcaron /Tcedilla /Udblacute /Uring - /Ydieresis /Zacute /Zcaron /Zdot - /IJ /Idot /dmacron /section -% 0xA0 - /abreve /aogonek /cacute /ccaron - /dcaron /ecaron /eogonek /gbreve - /lacute /lcaron /lslash /nacute - /ncaron /eng /odblacute /racute -% 0xB0 - /rcaron /sacute /scaron /scedilla - /tcaron /tcedilla /udblacute /uring - /ydieresis /zacute /zcaron /zdot - /ij /exclamdown /questiondown /sterling -% 0xC0 - /Agrave /Aacute /Acircumflex /Atilde - /Adieresis /Aring /AE /Ccedilla - /Egrave /Eacute /Ecircumflex /Edieresis - /Igrave /Iacute /Icircumflex /Idieresis -% 0xD0 - /Eth /Ntilde /Ograve /Oacute - /Ocircumflex /Otilde /Odieresis /OE - /Oslash /Ugrave /Uacute /Ucircumflex - /Udieresis /Yacute /Thorn /Germandbls -% 0xE0 - /agrave /aacute /acircumflex /atilde - /adieresis /aring /ae /ccedilla - /egrave /eacute /ecircumflex /edieresis - /igrave /iacute /icircumflex /idieresis -% 0xF0 - /eth /ntilde /ograve /oacute - /ocircumflex /otilde /odieresis /oe - /oslash /ugrave /uacute /ucircumflex - /udieresis /yacute /thorn /germandbls -] def - -% eof diff --git a/pandatool/src/egg-mkfont/charBitmap.cxx b/pandatool/src/egg-mkfont/charBitmap.cxx deleted file mode 100644 index ec4e169324..0000000000 --- a/pandatool/src/egg-mkfont/charBitmap.cxx +++ /dev/null @@ -1,76 +0,0 @@ -// Filename: charBitmap.cxx -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#include "charBitmap.h" - -#include - - -//////////////////////////////////////////////////////////////////// -// Function: CharBitmap::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -CharBitmap:: -CharBitmap(int character, int width, int height, - int hoff, int voff, double dx, double dy) { - _character = character; - _hoff = hoff; - _voff = voff; - _dx = dx; - _dy = dy; - - for (int y = 0; y < height; y++) { - _block.push_back(Row(width)); - } - - _x = 0; - _y = 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: CharBitmap::paint -// Access: Public -// Description: Paints a string of same-color pixels into the bitmap. -// This is called repeatedly by the rle decoder. -// Returns true when the last pixel has been painted, -// false if there is more to go. -//////////////////////////////////////////////////////////////////// -bool CharBitmap:: -paint(bool black, int num_pixels, int &repeat) { - if (_y < _block.size()) { - while (num_pixels > 0 && _y < _block.size()) { - nassertr(_x < _block[_y].size(), true); - _block[_y][_x] = black; - _x++; - if (_x >= _block[_y].size()) { - // End of a row. - _x = 0; - _y++; - while (repeat > 0 && _y < _block.size()) { - _block[_y] = _block[_y-1]; - _y++; - repeat--; - } - } - num_pixels--; - } - } - - return (_y < _block.size()); -} diff --git a/pandatool/src/egg-mkfont/charBitmap.h b/pandatool/src/egg-mkfont/charBitmap.h deleted file mode 100644 index 2c45f63c73..0000000000 --- a/pandatool/src/egg-mkfont/charBitmap.h +++ /dev/null @@ -1,56 +0,0 @@ -// Filename: charBitmap.h -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - - -#ifndef CHARBITMAP_H -#define CHARBITMAP_H - -#include - -#include "pvector.h" - -//////////////////////////////////////////////////////////////////// -// Class : CharBitmap -// Description : This defines a single character read from the PK -// file. It stores the kerning information as well as -// the character's decoded bitmap. -//////////////////////////////////////////////////////////////////// -class CharBitmap { -public: - typedef pvector Row; - typedef pvector Block; - - CharBitmap(int character, int width, int height, - int hoff, int voff, double dx, double dy); - - bool paint(bool black, int num_pixels, int &repeat); - - INLINE int get_width() const; - INLINE int get_height() const; - - int _character; - int _hoff, _voff; - double _dx, _dy; - - Block _block; - unsigned int _x, _y; -}; - -#include "charBitmap.I" - -#endif diff --git a/pandatool/src/egg-mkfont/charLayout.cxx b/pandatool/src/egg-mkfont/charLayout.cxx deleted file mode 100644 index 3c85027027..0000000000 --- a/pandatool/src/egg-mkfont/charLayout.cxx +++ /dev/null @@ -1,127 +0,0 @@ -// Filename: charLayout.cxx -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#include "charLayout.h" -#include "charBitmap.h" - -#include - -//////////////////////////////////////////////////////////////////// -// Function: CharLayout::reset -// Access: Public -// Description: Removes all the characters already placed on the -// layout, and resets the parameters for a new attempt. -//////////////////////////////////////////////////////////////////// -void CharLayout:: -reset(int working_xsize, int working_ysize, int working_buffer_pixels) { - _working_xsize = working_xsize; - _working_ysize = working_ysize; - _working_buffer_pixels = working_buffer_pixels; - - _placements.clear(); - - _cx = _working_buffer_pixels; - _cy = _working_buffer_pixels; - _nexty = _cy; -} - -//////////////////////////////////////////////////////////////////// -// Function: CharLayout::place_character -// Access: Public -// Description: Given a character bitmap and font metrics extracted -// from the pk file, find a place for it on the layout. -// Returns true if the character was placed, false if we -// ran out of room. -//////////////////////////////////////////////////////////////////// -bool CharLayout:: -place_character(const CharBitmap *bm) { - int width = bm->get_width() + _working_buffer_pixels; - int height = bm->get_height() + _working_buffer_pixels; - - int x, y; - if (find_hole(x, y, width, height)) { - _placements.push_back(CharPlacement(bm, x, y, width, height)); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: CharLayout::find_hole -// Access: Private -// Description: Searches for a hole of at least x_size by y_size -// pixels somewhere within the layout. If a -// suitable hole is found, sets x and y to the top left -// corner and returns true; otherwise, returns false. -//////////////////////////////////////////////////////////////////// -bool CharLayout:: -find_hole(int &x, int &y, int x_size, int y_size) const { - y = _working_buffer_pixels; - while (y + y_size <= _working_ysize) { - int next_y = _working_ysize; - // Scan along the row at 'y'. - x = _working_buffer_pixels; - while (x + x_size <= _working_xsize) { - int next_x = x; - - // Consider the spot at x, y. - const CharPlacement *overlap = find_overlap(x, y, x_size, y_size); - - if (overlap == (const CharPlacement *)NULL) { - // Hooray! - return true; - } - - next_x = overlap->_x + overlap->_width; - next_y = min(next_y, overlap->_y + overlap->_height); - nassertr(next_x > x, false); - x = next_x; - } - - nassertr(next_y > y, false); - y = next_y; - } - - // Nope, wouldn't fit anywhere. - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: CharLayout::find_overlap -// Access: Private -// Description: If the rectangle whose top left corner is x, y and -// whose size is x_size, y_size describes an empty hole -// that does not overlap any placed chars, returns -// NULL; otherwise, returns the first placed texture -// that the image does overlap. It is assumed the -// rectangle lies completely within the boundaries of -// the image itself. -//////////////////////////////////////////////////////////////////// -const CharPlacement *CharLayout:: -find_overlap(int x, int y, int x_size, int y_size) const { - Placements::const_iterator pi; - for (pi = _placements.begin(); pi != _placements.end(); ++pi) { - const CharPlacement &placement = (*pi); - if (placement.intersects(x, y, x_size, y_size)) { - return &placement; - } - } - - return (const CharPlacement *)NULL; -} diff --git a/pandatool/src/egg-mkfont/charLayout.h b/pandatool/src/egg-mkfont/charLayout.h deleted file mode 100644 index 4d733fb9af..0000000000 --- a/pandatool/src/egg-mkfont/charLayout.h +++ /dev/null @@ -1,55 +0,0 @@ -// Filename: charLayout.h -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#ifndef CHARLAYOUT_H -#define CHARLAYOUT_H - -#include - -#include "charPlacement.h" - -#include "pvector.h" - -class CharPlacement; - -//////////////////////////////////////////////////////////////////// -// Class : CharLayout -// Description : This represents the arrangement of all characters on -// a working bitmap of a given size. Either all -// characters fit or they don't. -//////////////////////////////////////////////////////////////////// -class CharLayout { -public: - void reset(int working_xsize, int working_ysize, - int working_buffer_pixels); - - bool place_character(const CharBitmap *bm); - - typedef pvector Placements; - Placements _placements; - - int _working_xsize, _working_ysize; - int _working_buffer_pixels; - int _cx, _cy, _nexty; - -private: - bool find_hole(int &x, int &y, int x_size, int y_size) const; - const CharPlacement *find_overlap(int x, int y, int x_size, int y_size) const; -}; - -#endif diff --git a/pandatool/src/egg-mkfont/charPlacement.cxx b/pandatool/src/egg-mkfont/charPlacement.cxx deleted file mode 100644 index ccb09e1bbf..0000000000 --- a/pandatool/src/egg-mkfont/charPlacement.cxx +++ /dev/null @@ -1,41 +0,0 @@ -// Filename: charPlacement.cxx -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#include "charPlacement.h" -#include "charBitmap.h" - - -//////////////////////////////////////////////////////////////////// -// Function: CharPlacement::intersects -// Access: Public -// Description: Returns true if the particular position this char -// has been assigned to overlaps the rectangle whose -// top left corner is at x, y and whose size is given by -// x_size, y_size, or false otherwise. -//////////////////////////////////////////////////////////////////// -bool CharPlacement:: -intersects(int x, int y, int x_size, int y_size) const { - int hright = x + x_size; - int hbot = y + y_size; - - int mright = _x + _width; - int mbot = _y + _height; - - return !(x >= mright || hright <= _x || - y >= mbot || hbot <= _y); -} diff --git a/pandatool/src/egg-mkfont/charPlacement.h b/pandatool/src/egg-mkfont/charPlacement.h deleted file mode 100644 index 9dbae51e3c..0000000000 --- a/pandatool/src/egg-mkfont/charPlacement.h +++ /dev/null @@ -1,48 +0,0 @@ -// Filename: charPlacement.h -// Created by: drose (16Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#ifndef CHARPLACEMENT_H -#define CHARPLACEMENT_H - -#include - -#include "charBitmap.h" - -//////////////////////////////////////////////////////////////////// -// Class : CharPlacement -// Description : This specifies where a particular character will be -// placed on the working bitmap. An array of these is -// built up to lay out all the characters in the bitmap, -// and then when the layout is suitable, the bitmap is -// generated. -//////////////////////////////////////////////////////////////////// -class CharPlacement { -public: - INLINE CharPlacement(const CharBitmap *bm, int x, int y, - int width, int height); - - bool intersects(int x, int y, int x_size, int y_size) const; - - const CharBitmap *_bm; - int _x, _y; - int _width, _height; -}; - -#include "charPlacement.I" - -#endif diff --git a/pandatool/src/egg-mkfont/egg-mkfont_composite1.cxx b/pandatool/src/egg-mkfont/egg-mkfont_composite1.cxx index 04d5252a1d..dbff12e568 100644 --- a/pandatool/src/egg-mkfont/egg-mkfont_composite1.cxx +++ b/pandatool/src/egg-mkfont/egg-mkfont_composite1.cxx @@ -1,7 +1,2 @@ -#include "charBitmap.cxx" -#include "charLayout.cxx" -#include "charPlacement.cxx" #include "eggMakeFont.cxx" -#include "fontFile.cxx" -#include "pkFontFile.cxx" diff --git a/pandatool/src/egg-mkfont/eggMakeFont.cxx b/pandatool/src/egg-mkfont/eggMakeFont.cxx index dcc6201a51..5c309c9a25 100644 --- a/pandatool/src/egg-mkfont/eggMakeFont.cxx +++ b/pandatool/src/egg-mkfont/eggMakeFont.cxx @@ -17,19 +17,16 @@ //////////////////////////////////////////////////////////////////// #include "eggMakeFont.h" -#include "charBitmap.h" -#include "charPlacement.h" -#include "pkFontFile.h" - -#include "string_utils.h" +#include "rangeIterator.h" +#include "pnmTextMaker.h" +#include "pnmTextGlyph.h" #include "eggGroup.h" +#include "eggPoint.h" +#include "eggPolygon.h" #include "eggTexture.h" #include "eggVertexPool.h" -#include "eggPolygon.h" -#include "eggPoint.h" -#include "pointerTo.h" - -#include +#include "eggVertex.h" +#include "string_utils.h" //////////////////////////////////////////////////////////////////// // Function: EggMakeFont::Constructor @@ -39,36 +36,31 @@ EggMakeFont:: EggMakeFont() : EggWriter(true, false) { set_program_description - ("egg-mkfont reads a rasterized font stored in a " - "Metafont/TeX pk file format, and generates an egg " - "file and corresponding texture map that can be used with " - "Panda's TextNode object to render text in the font.\n\n" - - "The input pk file can come from any of a number of sources. " - "It may be a Metafont font that ships with TeX, or it may " - "have been converted from a PostScript font, or you can use " - "freetype (see www.freetype.org) to convert a TTF font to pk.\n\n"); + ("egg-mkfont uses the FreeType library to generate an egg file " + "and a series of texture images from a font file " + "input, such as a TTF file. The resulting egg file " + "can be loaded in Panda as a StaticTextFont object for " + "rendering text, even if FreeType is not compiled into " + "the executing Panda.\n\n" + "It is strongly recommended that the resulting egg file " + "be subsequently passed through egg-palettize to consolidate the many " + "generated texture images into a single texture image to " + "improve rendering performance. This can also reduce the " + "texture images to achieve antialiasing."); clear_runlines(); - add_runline("[opts] -o output.egg file.pk"); - add_runline("[opts] file.pk output.egg"); + add_runline("[opts] -o output.egg font"); + add_runline("[opts] font output.egg"); add_option - ("i", "filename", 0, - "Name of the texture image to write. The default if this is omitted " - "is based on the name of the egg file.", - &EggMakeFont::dispatch_filename, NULL, &_output_image_filename); - - add_option - ("c", "num", 0, - "Specifies the number of channels of the output image. This should " - "either 1, 2, 3, or 4. If the number is 1 or 3 a grayscale image is " - "generated, with the text in white on black. If the number is 2 or 4 " - "a completely white image is generated, with the text in the alpha " - "channel. This parameter may also be specified as the third number " - "on -d, below. The default is 1.", - &EggMakeFont::dispatch_int, NULL, &_output_zsize); + ("i", "pattern", 0, + "The pattern to be used to generate the texture images. This string " + "will be passed to sprintf to generate the actual file name; it " + "should contain the string %d or %x (or some variant such as %03d) " + "which will be filled in with the Unicode number of each symbol. " + "If it is omitted, the default is based on the name of the egg file.", + &EggMakeFont::dispatch_string, NULL, &_output_image_pattern); add_option ("fg", "r,g,b[,a]", 0, @@ -80,115 +72,81 @@ EggMakeFont() : EggWriter(true, false) { add_option ("bg", "r,g,b[,a]", 0, "Specifies the background color of the generated texture map. The " - "default is transparent black: 0,0,0,0, which allows the text to be " + "default is transparent: 1,1,1,0, which allows the text to be " "visible against any color background by placing a polygon of a " - "suitable color behind it.", + "suitable color behind it. If the alpha component of either -fg " + "or -bg is not 1, the generated texture images will include an " + "alpha component; if both colors specify an alpha component of 1 " + "(or do not specify an alpha compenent), then the generated images " + "will not include an alpha component.", &EggMakeFont::dispatch_color, NULL, &_bg[0]); add_option - ("d", "x,y[,c]", 0, - "Dimensions in pixels of the texture image, with an optional number of " - "channels. Normally, you should not specify this parameter, as " - "egg-mkfont will choose an image size that yields a scale factor " - "between 2.5 and 4, which leads to good antialiased letters. If you " - "want a larger or smaller image, you could force the image size " - "with this parameter, but it would probably yield better results if " - "you re-rasterized the font at a different DPI instead.", - &EggMakeFont::dispatch_dimensions, &_got_output_size); + ("chars", "range", 0, + "Specifies the characters of the font that are used. The range " + "specification may include combinations of decimal or hex unicode " + "values (where hex values are identified with a leading 0x), separated " + "by commas and hyphens to indicate ranges, e.g. '32-126,0xfa0-0xfff'. " + "It also may specify ranges of ASCII characters by enclosing them " + "within square brackets, e.g. '[A-Za-z0-9]'. If this is not specified, " + "the default is the set of ASCII characters.", + &EggMakeFont::dispatch_range, NULL, &_range); + + add_option + ("ppu", "pixels", 0, + "Specify the pixels per unit. This is the number of pixels in the " + "generated texture map that are used for each onscreen unit (or each " + "10 points of font; see -ps). Setting this number larger results in " + "an easier-to-read font, but at the cost of more texture memory.", + &EggMakeFont::dispatch_double, NULL, &_pixels_per_unit); + + add_option + ("ps", "size", 0, + "Specify the point size of the resulting font. This controls the " + "apparent size of the font when it is rendered onscreen. By convention, " + "a 10 point font is 1 screen unit high.", + &EggMakeFont::dispatch_double, NULL, &_point_size); + + add_option + ("bp", "n", 0, + "The number of extra pixels around a single character in the " + "generated polygon. [1.0]", + &EggMakeFont::dispatch_double, NULL, &_poly_margin); + + add_option + ("bt", "n", 0, + "The number of extra pixels around each character in the texture map.", + &EggMakeFont::dispatch_double, NULL, &_tex_margin); add_option ("sf", "factor", 0, - "The scale factor of the generated image. This is the factor by which " "the font image is generated oversized, then reduced to its final size, " - "to generate antialiased letters. Values between 2.5 and 4 are generally " - "best. Normally, you should not specify this parameter, as egg-mkfont " - "will choose a scale factor automatically to best fit the letters in the " - "space available. If you do specify a scale factor with -sf, you must " - "also specify an image size with -d.", - &EggMakeFont::dispatch_double, &_got_scale_factor, &_scale_factor); + "to improve antialiasing. If the specified font contains one " + "or more fixed-size fonts instead of a scalable font, the scale factor " + "may be automatically adjusted as necessary to scale the closest-" + "matching font to the desired pixel size.", + &EggMakeFont::dispatch_double, NULL, &_scale_factor); add_option - ("nr", "", 0, - "No reduce. After the oversized image is generated, rather than reducing " - "it to its final size, just leave it as it is, and assume the user will " - "reduce it later. This may be desireable if you intend to adjust the " - "letters by hand in some way after the image is generated.", - &EggMakeFont::dispatch_none, &_no_reduce); - - add_option - ("g", "radius", 0, - "The radius of the Gaussian filter used to antialias the letters. [1.2]", - &EggMakeFont::dispatch_double, NULL, &_gaussian_radius); - - add_option - ("b", "n", 0, - "The number of buffer pixels between two adjacent characters in " - "the palette image. [4.0]", - &EggMakeFont::dispatch_double, NULL, &_buffer_pixels); - - add_option - ("B", "n", 0, - "The number of extra pixels around a single character in the " - "generated polygon. [1.0]", - &EggMakeFont::dispatch_double, NULL, &_poly_pixels); - - add_option - ("ds", "size", 0, - "Specify the design size of the resulting font. The design size of " - "a font is the height of a typical capital letter; it's the approximate " - "height of a line of text. This sets the size of the polygons " - "accordingly. [1.0]", - &EggMakeFont::dispatch_double, NULL, &_ds); - - add_option - ("scale", "size", 0, - "Specify an additional scale to the font, without changing its design " - "size. This makes the letters larger (or smaller) without changing " - "the spacing between lines. Usually you should use -ds instead of " - "-scale to change the size of the text.", - &EggMakeFont::dispatch_double, NULL, &_scale); - - add_option - ("all", "", 0, - "Extract all the characters in the font. Normally, only the " - "ASCII characters in the range 33 .. 127 are extracted.", - &EggMakeFont::dispatch_none, &_get_all); - - add_option - ("only", "'chars'", 0, - "Extract *only* the indicated characters from the font. The parameter " - "should be a quoted string of letters and symbols that are to be " - "extracted. If the hyphen appears, it indicates a range of characters, " - "e.g. A-Z to extract all the capital letters. If the hyphen appears " - "as the first or last character it loses its special meaning.", - &EggMakeFont::dispatch_string, NULL, &_only_chars); - - add_option - ("sc", "", 0, - "Small caps: generate lowercase letters as small capitals. This " - "allows the lowercase and capital letters to share the same space " - "on the texture map.", - &EggMakeFont::dispatch_none, &_small_caps); - - add_option - ("scs", "", 0, - "Small caps scale: the ratio of the size of a lowercase letter to " - "its uppercase equivalent, when -sc is in effect. [0.8]", - &EggMakeFont::dispatch_double, NULL, &_small_caps_scale); + ("face", "index", 0, + "Specify the face index of the particular face within the font file " + "to use. Some font files contain multiple faces, indexed beginning " + "at 0. The default is face 0.", + &EggMakeFont::dispatch_int, NULL, &_face_index); _fg.set(1.0, 1.0, 1.0, 1.0); - _bg.set(0.0, 0.0, 0.0, 0.0); - _output_xsize = 256; - _output_ysize = 256; - _output_zsize = 1; - _buffer_pixels = 4.0; - _poly_pixels = 1.0; - _scale_factor = 3.0; - _gaussian_radius = 1.2; - _ds = 1.0; - _scale = 1.0; - _small_caps_scale = 0.8; + _bg.set(1.0, 1.0, 1.0, 0.0); + _pixels_per_unit = 30.0; + _point_size = 10.0; + _poly_margin = 1.0; + _tex_margin = 2.0; + _scale_factor = 2.0; + _face_index = 0; + + _text_maker = NULL; + _vpool = NULL; + _group = NULL; } @@ -203,7 +161,7 @@ EggMakeFont() : EggWriter(true, false) { bool EggMakeFont:: handle_args(ProgramBase::Args &args) { if (args.empty()) { - nout << "Must specify name of pk file on command line.\n"; + nout << "Must specify name of font file on command line.\n"; return false; } @@ -213,73 +171,100 @@ handle_args(ProgramBase::Args &args) { } //////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::dispatch_dimensions -// Access: Protected, Static -// Description: Reads the dimensions of the output image and stores -// them in _output_[xyz]size. +// Function: EggMakeFont::run +// Access: Public +// Description: //////////////////////////////////////////////////////////////////// -bool EggMakeFont:: -dispatch_dimensions(ProgramBase *self, const string &opt, const string &arg, void *) { - EggSingleBase *base = (EggSingleBase *)self; - EggMakeFont *me = (EggMakeFont *)base->as_writer(); - return me->ns_dispatch_dimensions(opt, arg); -} +void EggMakeFont:: +run() { + _text_maker = new PNMTextMaker(_input_font_filename, _face_index); + if (!_text_maker->is_valid()) { + exit(1); + } + _text_maker->set_point_size(_point_size); + _text_maker->set_scale_factor(_scale_factor); + _text_maker->set_pixels_per_unit(_pixels_per_unit); -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::ns_dispatch_dimensions -// Access: Protected -// Description: Reads the dimensions of the output image and stores -// them in _output_[xyz]size. -//////////////////////////////////////////////////////////////////// -bool EggMakeFont:: -ns_dispatch_dimensions(const string &opt, const string &arg) { - vector_string words; - tokenize(arg, words, ","); - - bool okflag = false; - if (words.size() == 2) { - okflag = - string_to_int(words[0], _output_xsize) && - string_to_int(words[1], _output_ysize); - - } else if (words.size() == 3) { - okflag = - string_to_int(words[0], _output_xsize) && - string_to_int(words[1], _output_ysize) && - string_to_int(words[2], _output_zsize); + if (_range.is_empty()) { + // If there's no specified range, the default is the entire ASCII + // set. + _range.add_range(0x20, 0x7e); + } + if (_output_image_pattern.empty()) { + // Create a default texture filename pattern. + _output_image_pattern = _input_font_filename.get_fullpath_wo_extension() + "%03d.rgb"; } - if (!okflag) { - nout << "-" << opt - << " requires two or three integers separated by commas.\n"; - return false; - } + // Figure out how many channels we need based on the foreground and + // background colors. + bool needs_alpha = (_fg[3] != 1.0 || _bg[3] != 1.0); + bool needs_color = (_fg[0] != _fg[1] || _fg[1] != _fg[2] || + _bg[0] != _bg[1] || _bg[1] != _bg[2]); + if (needs_alpha) { + if (needs_color) { + _num_channels = 4; + _format = EggTexture::F_rgba; + } else { + if (_fg[0] == 1.0 && _bg[0] == 1.0) { + // A special case: we only need an alpha channel. Copy the + // alpha data into the color channels so we can write out a + // one-channel image. + _fg[0] = _fg[1] = _fg[2] = _fg[3]; + _bg[0] = _bg[1] = _bg[2] = _bg[3]; + _num_channels = 1; + _format = EggTexture::F_alpha; + } else { + _num_channels = 2; + _format = EggTexture::F_luminance_alpha; + } + } + } else { + if (needs_color) { + _num_channels = 3; + _format = EggTexture::F_rgb; + } else { + _num_channels = 1; + _format = EggTexture::F_luminance; + } + } - return true; + _group = new EggGroup(); + _data.add_child(_group); + + _vpool = new EggVertexPool("vpool"); + _group->add_child(_vpool); + + // Make the group a sequence, as a convenience. If we view the + // egg file directly we can see all the characters one at a time. + _group->set_switch_flag(true); + _group->set_switch_fps(2.0); + + // Also create an egg group indicating the font's design size. + EggGroup *ds_group = new EggGroup("ds"); + _group->add_child(ds_group); + EggVertex *vtx = make_vertex(LPoint2d(0.0, _text_maker->get_line_height())); + EggPoint *point = new EggPoint; + ds_group->add_child(point); + point->add_vertex(vtx); + + // Finally, add the characters, one at a time. + RangeIterator ri(_range); + do { + add_character(ri.get_code()); + } while (ri.next()); + + write_egg_file(); } //////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::get_uv -// Access: Private -// Description: Given the X, Y coordinates of a particular pixel on -// the image, return the corresponding UV coordinates. +// Function: EggMakeFont::dispatch_range +// Access: Private, Static +// Description: //////////////////////////////////////////////////////////////////// -TexCoordd EggMakeFont:: -get_uv(double x, double y) { - return TexCoordd(x / (double)_working_xsize, - ((double)_working_ysize - y) / (double)_working_ysize); -} - - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::get_xy -// Access: Private -// Description: Given X, Y coordinates in pixels, scale to unit -// coordinates for the character's geometry. -//////////////////////////////////////////////////////////////////// -LPoint2d EggMakeFont:: -get_xy(double x, double y) { - return LPoint2d(x / (_font->get_hppp() * _ppu), -y / (_font->get_vppp() * _ppu)); +bool EggMakeFont:: +dispatch_range(const string &, const string &arg, void *var) { + RangeDescription *ip = (RangeDescription *)var; + return ip->parse_parameter(arg); } //////////////////////////////////////////////////////////////////// @@ -296,550 +281,146 @@ make_vertex(const LPoint2d &xy) { } //////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::copy_character +// Function: EggMakeFont::add_character // Access: Private -// Description: Copy the indicated character image to its home on the -// bitmap and generate egg structures for it. +// Description: Generates the indicated character and adds it to the +// font description. //////////////////////////////////////////////////////////////////// void EggMakeFont:: -copy_character(const CharPlacement &pl) { - const CharBitmap *bm = pl._bm; - int xp = pl._x; - int yp = pl._y; - - int character = bm->_character; - int hoff = bm->_hoff; - int voff = bm->_voff; - double dx = bm->_dx; - double dy = bm->_dy; - int width = bm->get_width(); - int height = bm->get_height(); - - // Copy the character into the image. - if (_output_image.has_alpha()) { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (bm->_block[y][x]) { - _output_image.set_xel(xp + x, yp + y, _fg[0], _fg[1], _fg[2]); - _output_image.set_alpha(xp + x, yp + y, _fg[3]); - } - } - } - } else { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (bm->_block[y][x]) { - _output_image.set_xel(xp + x, yp + y, _fg[0], _fg[1], _fg[2]); - } - } - } +add_character(int code) { + PNMTextGlyph *glyph = _text_maker->get_glyph(code); + if (glyph == (PNMTextGlyph *)NULL) { + nout << "No definition in font for character " << code << ".\n"; + return; } - // Create the polygon that will have the character mapped onto it. + make_geom(glyph, code); +} - // b is the number of pixels bigger than the character in each - // direction the polygon will be. It needs to be larger than zero - // just because when we filter the image down, we end up with some - // antialiasing blur that extends beyond the original borders of the - // character. But it shouldn't be too large, because we don't want - // the neighboring polygons of a word to overlap any more than they - // need to. - - double b = _working_poly_pixels; - - TexCoordd uv_ul = get_uv(xp - b, yp - b); - TexCoordd uv_lr = get_uv(xp + width + b, yp + height + b); - LPoint2d xy_ul = get_xy(-hoff - b, -voff - b); - LPoint2d xy_lr = get_xy(-hoff + width + b, -voff + height + b); - LPoint2d dp = get_xy(dx, dy); - - EggVertex *v1 = make_vertex(LPoint2d(xy_ul[0], xy_lr[1])); - EggVertex *v2 = make_vertex(LPoint2d(xy_lr[0], xy_lr[1])); - EggVertex *v3 = make_vertex(LPoint2d(xy_lr[0], xy_ul[1])); - EggVertex *v4 = make_vertex(LPoint2d(xy_ul[0], xy_ul[1])); - - v1->set_uv(TexCoordd(uv_ul[0], uv_lr[1])); - v2->set_uv(TexCoordd(uv_lr[0], uv_lr[1])); - v3->set_uv(TexCoordd(uv_lr[0], uv_ul[1])); - v4->set_uv(TexCoordd(uv_ul[0], uv_ul[1])); +//////////////////////////////////////////////////////////////////// +// Function: EggMakeFont::make_geom +// Access: Private +// Description: Creates the actual geometry for the glyph. +//////////////////////////////////////////////////////////////////// +void EggMakeFont:: +make_geom(PNMTextGlyph *glyph, int character) { // Create an egg group to hold the polygon. string group_name = format_string(character); - PT(EggGroup) group = new EggGroup(group_name); - _egg_defs[character] = group; - - EggPolygon *poly = new EggPolygon(); - group->add_child(poly); - poly->set_texture(_tref); - - poly->add_vertex(v1); - poly->add_vertex(v2); - poly->add_vertex(v3); - poly->add_vertex(v4); - - // Now create a single point where the origin of the next character - // will be. - - EggVertex *v0 = make_vertex(dp); - EggPoint *point = new EggPoint; - group->add_child(point); - point->add_vertex(v0); - - if (_small_caps && isupper(character)) { - // Now create the polygon representing the lowercase letter, for - // small caps mode. This uses the same texture on a smaller - // polygon. - xy_ul *= _small_caps_scale; - xy_lr *= _small_caps_scale; - dp *= _small_caps_scale; - character = tolower(character); - - EggVertex *v1 = make_vertex(LPoint2d(xy_ul[0], xy_lr[1])); - EggVertex *v2 = make_vertex(LPoint2d(xy_lr[0], xy_lr[1])); - EggVertex *v3 = make_vertex(LPoint2d(xy_lr[0], xy_ul[1])); - EggVertex *v4 = make_vertex(LPoint2d(xy_ul[0], xy_ul[1])); - - v1->set_uv(TexCoordd(uv_ul[0], uv_lr[1])); - v2->set_uv(TexCoordd(uv_lr[0], uv_lr[1])); - v3->set_uv(TexCoordd(uv_lr[0], uv_ul[1])); - v4->set_uv(TexCoordd(uv_ul[0], uv_ul[1])); - - string group_name = format_string(character); - PT(EggGroup) group = new EggGroup(group_name); - _egg_defs[character] = group; + EggGroup *group = new EggGroup(group_name); + _group->add_child(group); + if (glyph->get_width() != 0 && glyph->get_height() != 0) { + int bitmap_top = glyph->get_top(); + int bitmap_left = glyph->get_left(); + double tex_x_size = glyph->get_width(); + double tex_y_size = glyph->get_height(); + + double poly_margin = _poly_margin; + double x_origin = _tex_margin; + double y_origin = _tex_margin; + double page_y_size = tex_y_size + _tex_margin * 2; + double page_x_size = tex_x_size + _tex_margin * 2; + + // Determine the corners of the rectangle in geometric units. + double tex_poly_margin = poly_margin / _pixels_per_unit; + double origin_y = bitmap_top / _pixels_per_unit; + double origin_x = bitmap_left / _pixels_per_unit; + double top = origin_y + tex_poly_margin; + double left = origin_x - tex_poly_margin; + double bottom = origin_y - tex_y_size / _pixels_per_unit - tex_poly_margin; + double right = origin_x + tex_x_size / _pixels_per_unit + tex_poly_margin; + + // And the corresponding corners in UV units. + double uv_top = 1.0f - (double)(y_origin - poly_margin) / page_y_size; + double uv_left = (double)(x_origin - poly_margin) / page_x_size; + double uv_bottom = 1.0f - (double)(y_origin + poly_margin + tex_y_size) / page_y_size; + double uv_right = (double)(x_origin + poly_margin + tex_x_size) / page_x_size; + + // Create the vertices for the polygon. + EggVertex *v1 = make_vertex(LPoint2d(left, bottom)); + EggVertex *v2 = make_vertex(LPoint2d(right, bottom)); + EggVertex *v3 = make_vertex(LPoint2d(right, top)); + EggVertex *v4 = make_vertex(LPoint2d(left, top)); + + v1->set_uv(TexCoordd(uv_left, uv_bottom)); + v2->set_uv(TexCoordd(uv_right, uv_bottom)); + v3->set_uv(TexCoordd(uv_right, uv_top)); + v4->set_uv(TexCoordd(uv_left, uv_top)); + EggPolygon *poly = new EggPolygon(); group->add_child(poly); - poly->set_texture(_tref); + poly->set_texture(get_tref(glyph, character)); poly->add_vertex(v1); poly->add_vertex(v2); poly->add_vertex(v3); poly->add_vertex(v4); - - EggVertex *v0 = make_vertex(dp); - EggPoint *point = new EggPoint; - group->add_child(point); - point->add_vertex(v0); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::consider_scale_factor -// Access: Private -// Description: Attempts to place all of the characters on an image -// of the indicated size (scaled up from the output -// image size by scale_factor in each dimension). -// Returns true if all the characters fit, or false if -// the image was too small. In either case, leaves -// _scale_factor and _working_* set to reflect the -// chosen scale factor. -//////////////////////////////////////////////////////////////////// -bool EggMakeFont:: -consider_scale_factor(double scale_factor) { - _scale_factor = scale_factor; - _working_xsize = (int)floor(_output_xsize * _scale_factor + 0.5); - _working_ysize = (int)floor(_output_ysize * _scale_factor + 0.5); - _working_buffer_pixels = (int)floor(_buffer_pixels * _scale_factor + 0.5); - - _layout.reset(_working_xsize, _working_ysize, _working_buffer_pixels); - - bool ok = true; - int num_chars = _font->get_num_chars(); - for (int i = 0; i < num_chars; i++) { - CharBitmap *bm = _font->get_char(i); - if (!(_small_caps && islower(bm->_character))) { - ok = _layout.place_character(bm); - if (!ok) { - // Out of room. - return false; - } - } } - // They all fit! - return true; -} + // Now create a single point where the origin of the next character + // will be. -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::choose_scale_factor -// Access: Private -// Description: Binary search on scale factor, given a factor that is -// known to be too small and one that is known to be too -// large. -//////////////////////////////////////////////////////////////////// -void EggMakeFont:: -choose_scale_factor(double too_small, double too_large) { - if (too_large - too_small < 0.000001) { - // Close enough. - consider_scale_factor(too_large); - return; - } - - double mid = (too_small + too_large) / 2.0; - if (consider_scale_factor(mid)) { - // This midpoint is too large. - choose_scale_factor(too_small, mid); - } else { - // This midpoint is too small. - choose_scale_factor(mid, too_large); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::choose_scale_factor -// Access: Private -// Description: Tries several scale_factors until an optimal one -// (that is, the smallest one that all letters fit -// within) is found. Returns when all characters have -// been successfully placed on the layout. -// -// Returns true if successful, or false if it just could -// not be done. -//////////////////////////////////////////////////////////////////// -bool EggMakeFont:: -choose_scale_factor() { - // We need to determine a scale factor that will definitely be too - // small, and one that will definitely be too large. - double too_small, too_large; - int sanity_count = 0; - - double guess = 1.0; - if (consider_scale_factor(guess)) { - // This guess is too large. - do { - too_large = guess; - guess = guess / 2.0; - if (sanity_count++ > 20) { - return false; - } - } while (consider_scale_factor(guess)); - too_small = guess; - - } else { - // This guess is too small. - do { - too_small = guess; - guess = guess * 2.0; - if (sanity_count++ > 20) { - return false; - } - } while (!consider_scale_factor(guess)); - too_large = guess; - } - - choose_scale_factor(too_small, too_large); - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::choose_image_size -// Access: Private -// Description: Chooses a size for the output image that should yield -// a scale_factor in the range (2.5 .. 4], which will give -// pretty good antialiased letters. -//////////////////////////////////////////////////////////////////// -void EggMakeFont:: -choose_image_size() { - // Start with an arbitrary guess. - _output_xsize = 256; - _output_ysize = 256; - - bool sane = choose_scale_factor(); - - if (sane && _scale_factor <= 2.5) { - // The scale factor is too small. The letters may appear jaggy, - // and we don't need so much image space. - do { - if (_output_ysize < _output_xsize) { - _output_xsize /= 2; - } else { - _output_ysize /= 2; - } - sane = choose_scale_factor(); - } while (sane && _scale_factor <= 2.5); - - if (!sane) { - // Oops, better backpedal. - _output_xsize *= 2; - } - choose_scale_factor(); - - } else if (_scale_factor > 4.0) { - // The scale factor is too large. The letters will be overly - // reduced and may be blurry. We need a larger image. - do { - if (_output_ysize < _output_xsize) { - _output_ysize *= 2; - } else { - _output_xsize *= 2; - } - sane = choose_scale_factor(); - } while (!sane || _scale_factor > 4.0); - } -} - - - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::unsmooth_rgb -// Access: Public -// Description: Make the image jaggy in RGB (but leave it antialiased -// in alpha). This will result in correct antialiasing -// when the text is loaded in the player. -//////////////////////////////////////////////////////////////////// -void EggMakeFont:: -unsmooth_rgb(PNMImage &image) { - for (int y = 0; y < image.get_y_size(); y++) { - for (int x = 0; x < image.get_x_size(); x++) { - double alpha = image.get_alpha(x, y); - if (alpha != 0.0) { - image.set_xel(x, y, image.get_xel(x, y) / alpha); - } - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::expand_hyphen -// Access: Public -// Description: If a hyphen appears in the string anywhere but in the -// first and last position, replace it with a sequence -// of characters. For example, 0-9 becomes 0123456789. -// Return the new string. -//////////////////////////////////////////////////////////////////// -string EggMakeFont:: -expand_hyphen(const string &str) { - string result; - size_t last = 0; - - size_t hyphen = str.find('-', last + 1); - while (hyphen < str.length() - 1) { - size_t ap = hyphen - 1; - size_t zp = hyphen + 1; - result += str.substr(last, ap - last); - char a = str[ap]; - char z = str[zp]; - - for (char i = a; i <= z; i++) { - result += i; - } - - last = zp + 1; - hyphen = str.find('-', last + 1); - } - - result += str.substr(last); - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: EggMakeFont::run -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -void EggMakeFont:: -run() { - if (_output_image_filename.empty() && has_output_filename()) { - _output_image_filename = get_output_filename(); - _output_image_filename.set_extension("rgb"); - } - - if (_output_image_filename.empty()) { - nout << "No output image filename given.\n"; - exit(1); - } - - if (!_only_chars.empty()) { - _only_chars = expand_hyphen(_only_chars); - nout << "Extracting only characters: " << _only_chars << "\n"; - if (_small_caps) { - _only_chars = upcase(_only_chars); - } - } - - _font = new PkFontFile(); - if (!_font->read(_input_font_filename, _get_all, _only_chars)) { - nout << "Unable to read " << _input_font_filename << ".\n"; - exit(1); - } - - nout << "Placing " << _font->get_num_chars() << " letters.\n"; - - // Now that we've collected all the characters, sort them in order - // from tallest to shortest so we will hopefully get a more optimal - // packing. - _font->sort_chars_by_height(); - - - // Choose a suitable image size and/or scale factor. - if (_got_scale_factor && _got_output_size) { - // The user specified both; we accept the scale factor. - if (!consider_scale_factor(_scale_factor)) { - nout << "Ran out of room on font image; try increasing the image " - "size or the scale factor.\n"; - exit(1); - } - - } else if (_got_output_size) { - // The user specified an output size, but not a scale factor. - choose_scale_factor(); - - } else if (_got_scale_factor) { - // The user specified a scale factor, but not an output size. - // This is really an error. - nout << "It is meaningless to specify a scale factor (-sf) without " - "also specifying an image size (-d). Ignoring scale factor.\n"; - choose_image_size(); - - } else { - // The user did not specify anything. This is really preferred. - // We'll decide what's best. - choose_image_size(); - } - - _working_poly_pixels = _poly_pixels * _scale_factor; - _output_image.clear(_working_xsize, _working_ysize, _output_zsize); - - // If the user specified 1.0 for both foreground and background - // alpha, we don't really want to use alpha. - _use_alpha = (_output_zsize != 3) && (_fg[3] != 1.0 || _bg[3] != 1.0); - if (_use_alpha && _output_zsize == 1) { - // If we have only one channel and we're using alpha, then the - // gray channel becomes the alpha channel. - _fg[0] = _fg[3]; - _bg[0] = _bg[3]; - } - - _output_image.fill(_bg[0], _bg[1], _bg[2]); - if (_output_image.has_alpha()) { - _output_image.alpha_fill(_bg[3]); - } - - _group = new EggGroup(); - _data.add_child(_group); - _tref = new EggTexture("chars", _output_image_filename); - _group->add_child(_tref); - _vpool = new EggVertexPool("vpool"); - _group->add_child(_vpool); - - // Set the appropriate flags on the texture. - EggTexture::Format format = EggTexture::F_unspecified; - if (_use_alpha) { - switch (_output_zsize) { - case 1: - format = EggTexture::F_alpha; - break; - case 2: - format = EggTexture::F_luminance_alpha; - break; - case 4: - format = EggTexture::F_rgba; - break; - } - } else { - switch (_output_zsize) { - case 1: - case 2: - format = EggTexture::F_luminance; - break; - case 3: - case 4: - format = EggTexture::F_rgb; - break; - } - } - _tref->set_format(format); - - // Make the group a sequence, as a convenience. If we view the - // egg file directly we can see all the characters one at a time. - _group->set_switch_flag(true); - _group->set_switch_fps(2.0); - - // Compute the font points per polygon unit. - _ppu = _font->get_ds() / (_ds * _scale); - - // Now we can copy all the characters onto the actual image. - CharLayout::Placements::const_iterator pi; - for (pi = _layout._placements.begin(); - pi != _layout._placements.end(); - ++pi) { - copy_character(*pi); - } - - // And now put all the Egg structures we created into the egg file, - // in numeric order. - EggDefs::const_iterator edi; - for (edi = _egg_defs.begin(); edi != _egg_defs.end(); ++edi) { - _group->add_child((*edi).second.p()); - } - - // Also create an egg group indicating the font's design size. - EggGroup *ds_group = new EggGroup("ds"); - _group->add_child(ds_group); - EggVertex *vtx = make_vertex(LPoint2d(0.0, _ds)); + EggVertex *v0 = make_vertex(LPoint2d(glyph->get_advance() / _pixels_per_unit, 0.0)); EggPoint *point = new EggPoint; - ds_group->add_child(point); - point->add_vertex(vtx); - - if (_use_alpha && _output_zsize != 1) { - if (_bg[3] == 0.0) { - // If we have a transparent background, then everything in the - // color channels is pointless--the color information is - // completely replaced. Might as well fill it white. - _output_image.fill(_fg[0], _fg[1], _fg[2]); - - } else if (_bg[3] == 1.0) { - // Similarly if we have a transparent foreground. - _output_image.fill(_bg[0], _bg[1], _bg[2]); - } - } - - // All done! Write everything out. - nout << "Scale factor is " << _scale_factor << "\n"; - - if (_no_reduce) { - // Scaling of the final image forbidden by the user. - nout << "Image destination size is " << _output_xsize - << " by " << _output_ysize << " by " << _output_zsize - << "; not reducing.\n"; - nout << "Generating " << _working_xsize << " by " << _working_ysize - << " by " << _output_zsize << " image: " - << _output_image_filename << "\n"; - - _output_image.write(_output_image_filename); - - } else if (_output_xsize == _working_xsize && - _output_ysize == _working_ysize) { - // Scaling unnecessary, because the scale factor is 1.0. - nout << "Generating " << _output_xsize << " by " << _output_ysize - << " by " << _output_zsize << " image: " - << _output_image_filename << "\n"; - _output_image.write(_output_image_filename); - - } else { - // The normal path: reduce the final image by the scale factor to - // antialias the letters. - PNMImage small_image(_output_xsize, _output_ysize, _output_zsize); - small_image.gaussian_filter_from(_gaussian_radius, _output_image); - - // Fix antialiasing, if required. - if (_use_alpha && _bg[3] != 0.0 && _bg[3] != 1.0) { - // If we have some non-transparent background, we need to - // compensate for the antialiasing. - unsmooth_rgb(small_image); - } - - - nout << "Generating " << _output_xsize << " by " << _output_ysize - << " by " << _output_zsize << " image: " - << _output_image_filename << "\n"; - small_image.write(_output_image_filename); - } - - write_egg_file(); + group->add_child(point); + point->add_vertex(v0); } +//////////////////////////////////////////////////////////////////// +// Function: EggMakeFont::get_tref +// Access: Private +// Description: Returns the egg texture reference for a particular +// glyph, creating it if it has not already been +// created. +//////////////////////////////////////////////////////////////////// +EggTexture *EggMakeFont:: +get_tref(PNMTextGlyph *glyph, int character) { + TRefs::iterator ti = _trefs.find(glyph); + if (ti != _trefs.end()) { + return (*ti).second; + } + + EggTexture *tref = make_tref(glyph, character); + _trefs[glyph] = tref; + return tref; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggMakeFont::make_tref +// Access: Private +// Description: Writes out the texture image for an indicated glyph, +// and returns its egg reference. +//////////////////////////////////////////////////////////////////// +EggTexture *EggMakeFont:: +make_tref(PNMTextGlyph *glyph, int character) { + char buffer[1024]; + sprintf(buffer, _output_image_pattern.c_str(), character); + + Filename texture_filename = buffer; + PNMImage image(glyph->get_width() + _tex_margin * 2, + glyph->get_height() + _tex_margin * 2, _num_channels); + image.fill(_bg[0], _bg[1], _bg[2]); + if (image.has_alpha()) { + image.alpha_fill(_bg[3]); + } + glyph->place(image, -glyph->get_left() + _tex_margin, + glyph->get_top() + _tex_margin, _fg); + + if (!image.write(texture_filename)) { + nout << "Unable to write " << texture_filename << "\n"; + } + + EggTexture *tref = + new EggTexture(texture_filename.get_basename_wo_extension(), + texture_filename); + tref->set_format(_format); + tref->set_wrap_mode(EggTexture::WM_clamp); + tref->set_minfilter(EggTexture::FT_linear_mipmap_linear); + tref->set_magfilter(EggTexture::FT_linear); + + return tref; +} int main(int argc, char *argv[]) { EggMakeFont prog; diff --git a/pandatool/src/egg-mkfont/eggMakeFont.h b/pandatool/src/egg-mkfont/eggMakeFont.h index 8cd147802c..9eda436c7c 100644 --- a/pandatool/src/egg-mkfont/eggMakeFont.h +++ b/pandatool/src/egg-mkfont/eggMakeFont.h @@ -20,27 +20,25 @@ #define EGGMAKEFONT_H #include "pandatoolbase.h" - -#include "charLayout.h" +#include "rangeDescription.h" #include "eggWriter.h" -#include "luse.h" -#include "pnmImage.h" +#include "eggTexture.h" +#include "pmap.h" -class CharPlacement; -class CharBitmap; -class EggGroup; -class EggTexture; +class PNMTextMaker; +class PNMTextGlyph; class EggVertexPool; -class EggVertex; -class FontFile; +class EggGroup; //////////////////////////////////////////////////////////////////// // Class : EggMakeFont -// Description : This program reads a rasterized font stored in a -// Metafont/TeX pk file format, and generates an egg -// file and texture map that can be used with TextNode -// to render text using the font. +// Description : This program uses FreeType to generate an egg file +// and a series of texture images from a font file +// input, such as a TTF file. The resulting egg file +// can be loaded in Panda as a StaticTextFont object for +// rendering text, even if FreeType is not compiled into +// the executing Panda. //////////////////////////////////////////////////////////////////// class EggMakeFont : public EggWriter { public: @@ -48,62 +46,41 @@ public: protected: virtual bool handle_args(Args &args); - static bool dispatch_dimensions(ProgramBase *self, const string &opt, const string &arg, void *); - bool ns_dispatch_dimensions(const string &opt, const string &arg); - -private: - TexCoordd get_uv(double x, double y); - LPoint2d get_xy(double x, double y); - EggVertex *make_vertex(const LPoint2d &xy); - - void copy_character(const CharPlacement &pl); - - bool consider_scale_factor(double scale_factor); - void choose_scale_factor(double too_small, double too_large); - bool choose_scale_factor(); - void choose_image_size(); - - void unsmooth_rgb(PNMImage &image); - string expand_hyphen(const string &str); public: void run(); private: - Filename _output_image_filename; - Filename _input_font_filename; - bool _got_output_size; + static bool dispatch_range(const string &, const string &arg, void *var); + EggVertex *make_vertex(const LPoint2d &xy); + + void add_character(int code); + void make_geom(PNMTextGlyph *glyph, int character); + EggTexture *get_tref(PNMTextGlyph *glyph, int character); + EggTexture *make_tref(PNMTextGlyph *glyph, int character); + +private: Colorf _fg, _bg; - bool _use_alpha; - int _output_xsize, _output_ysize, _output_zsize; - double _buffer_pixels; - double _poly_pixels; - bool _got_scale_factor; + RangeDescription _range; + double _pixels_per_unit; + double _point_size; + double _poly_margin; + double _tex_margin; double _scale_factor; - bool _no_reduce; - double _gaussian_radius; - double _ds; - double _scale; - double _ppu; - bool _get_all; - string _only_chars; - bool _small_caps; - double _small_caps_scale; - FontFile *_font; - typedef pmap EggDefs; - EggDefs _egg_defs; - - CharLayout _layout; - int _working_xsize, _working_ysize; - int _working_buffer_pixels; - double _working_poly_pixels; - - PNMImage _output_image; + Filename _input_font_filename; + int _face_index; + string _output_image_pattern; + PNMTextMaker *_text_maker; + + EggTexture::Format _format; + int _num_channels; EggVertexPool *_vpool; EggGroup *_group; - EggTexture *_tref; + + typedef pmap TRefs; + TRefs _trefs; }; diff --git a/pandatool/src/egg-mkfont/fontFile.I b/pandatool/src/egg-mkfont/fontFile.I deleted file mode 100644 index 46304c0d05..0000000000 --- a/pandatool/src/egg-mkfont/fontFile.I +++ /dev/null @@ -1,91 +0,0 @@ -// Filename: fontFile.I -// Created by: drose (18Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_ds -// Access: Public -// Description: Returns the designed size of the font in points. -// This is the basic height of a line of text in the -// given font. -//////////////////////////////////////////////////////////////////// -INLINE double FontFile:: -get_ds() const { - return _ds; -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_dpi -// Access: Public -// Description: Returns the resolution of the rasterized font in dots -// per inch. This is mainly useful for user -// information; use get_vppp() and get_hppp() for more -// precises measurements. -//////////////////////////////////////////////////////////////////// -INLINE double FontFile:: -get_dpi() const { - return floor(_vppp * 72.27 + 0.5); -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_vppp -// Access: Public -// Description: Returns the vertical pixels per point of the -// rasterized font characters. This is the number of -// pixels high each bitmap characters is per point of -// font. -//////////////////////////////////////////////////////////////////// -INLINE double FontFile:: -get_vppp() const { - return _vppp; -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_hppp -// Access: Public -// Description: Returns the horizontal pixels per point of the -// rasterized font characters. This is the number of -// pixels wide each bitmap characters is per point of -// font. -//////////////////////////////////////////////////////////////////// -INLINE double FontFile:: -get_hppp() const { - return _hppp; -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_num_chars -// Access: Public -// Description: Returns the number of characters (glyphs) read from -// the font. -//////////////////////////////////////////////////////////////////// -INLINE int FontFile:: -get_num_chars() const { - return _chars.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::get_char -// Access: Public -// Description: Returns the nth character (glyph) read from the font. -//////////////////////////////////////////////////////////////////// -INLINE CharBitmap *FontFile:: -get_char(int n) const { - nassertr(n >= 0 && n < (int)_chars.size(), (CharBitmap *)NULL); - return _chars[n]; -} diff --git a/pandatool/src/egg-mkfont/fontFile.cxx b/pandatool/src/egg-mkfont/fontFile.cxx deleted file mode 100644 index 13b8947efe..0000000000 --- a/pandatool/src/egg-mkfont/fontFile.cxx +++ /dev/null @@ -1,67 +0,0 @@ -// Filename: fontFile.cxx -// Created by: drose (18Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#include "fontFile.h" -#include "charBitmap.h" - -#include - - -// An STL function object to sort the characters in order from tallest -// to shortest. This provides a more optimal packing into the -// resulting image. -class SortCharBitmap { -public: - bool operator() (const CharBitmap *c1, const CharBitmap *c2) const { - return (c1->get_height() > c2->get_height()); - } -}; - - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -FontFile:: -FontFile() { - // A standard design size for font types that don't specify - // otherwise. - _ds = 12.0; -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::Destructor -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -FontFile:: -~FontFile() { -} - -//////////////////////////////////////////////////////////////////// -// Function: FontFile::sort_chars_by_height -// Access: Public -// Description: Sorts the array of characters in the font as returned -// by get_char() so that the tallest ones appear first -// in the list. -//////////////////////////////////////////////////////////////////// -void FontFile:: -sort_chars_by_height() { - sort(_chars.begin(), _chars.end(), SortCharBitmap()); -} diff --git a/pandatool/src/egg-mkfont/fontFile.h b/pandatool/src/egg-mkfont/fontFile.h deleted file mode 100644 index 5398fc380c..0000000000 --- a/pandatool/src/egg-mkfont/fontFile.h +++ /dev/null @@ -1,65 +0,0 @@ -// Filename: fontFile.h -// Created by: drose (18Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#ifndef FONTFILE_H -#define FONTFILE_H - -#include - -#include -#include - -#include - -class CharBitmap; - -//////////////////////////////////////////////////////////////////// -// Class : FontFile -// Description : This is an abstract base class that provides the -// interface to reading and/or rasterizing a particular -// font file. -//////////////////////////////////////////////////////////////////// -class FontFile { -public: - FontFile(); - virtual ~FontFile(); - - virtual bool read(const Filename &filename, - bool extract_all, const string &extract_only)=0; - - INLINE double get_ds() const; - INLINE double get_dpi() const; - INLINE double get_vppp() const; - INLINE double get_hppp() const; - - void sort_chars_by_height(); - INLINE int get_num_chars() const; - INLINE CharBitmap *get_char(int n) const; - -protected: - double _ds; - double _vppp; - double _hppp; - - typedef pvector Chars; - Chars _chars; -}; - -#include "fontFile.I" - -#endif diff --git a/pandatool/src/egg-mkfont/pfb2egg b/pandatool/src/egg-mkfont/pfb2egg deleted file mode 100644 index 8363e42eaa..0000000000 --- a/pandatool/src/egg-mkfont/pfb2egg +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/sh -# -# Converts from a pair of Postscript font files (file.pfb and -# file.afm) to an egg file and associated texture map that is suitable -# for using with the TextNode class in Panda to render text in the -# world. -# -# Note that the pfb file is a Postscript font file, not to be confused -# with a Performer scene graph file (which also used the .pfb -# extension). This script has nothing to do with Performer. -# -# Both a pfb file and an afm file ("Adobe Font Metrics") must be -# supplied. Typically, Postscript fonts are shipped to Windows with a -# pfm file ("Printer Font Metrics") instead of an afm file. If this -# is the case, you must use a utility like CrossFont to convert the -# pfm to afm format. (Look to http://www.asy.com/ for CrossFont, or -# see http://www.sketchpad.net/fonts1.htm for a treatise on the -# subject.) -# -# This script takes advantage of afm2tfm and ps2pk, which I believe -# are typically shipped with TeX. -# -# -# Usage: -# -# pfb2egg [opts] file.pfb file.egg -- [mkfont-opts] -# -# Options that control the behavior of this script must appear first. -# The extra options options following the first two parameters are passed -# unchanged to egg-mkfont. -# -# The afm file is assumed to be the same name as the pfb file, with -# pfb replaced by afm. -# -# Local options: -# -# -d dpi -# Specify the resolution at which to rasterize the font before -# converting it. This affects the size of the generated texture -# image and, in turn, the clarity of the resulting font. The -# default is 720, which generally seems to be a good ratio. -# -# -p pointsize -# Specify the pointsize at which to convert the font. This doesn't -# make a whole lot of difference to its appearance other than -# scaling the dpi value, above, unless the font has a different -# appearance at smaller point sizes (some fonts include hints to -# change the way they are rendered at small point sizes). The -# default is 10. -# -# See egg-mkfont -h for a description of the additional options. -# -#ENDCOMMENT - -showhelp= -dpi=720 -pointsize=10 -while getopts "d:p:h" flag; do - case $flag in - d) dpi="$OPTARG";; - p) pointsize="$OPTARG";; - h) showhelp=y;; - \?) exit 1; - esac -done - -if [ -z "$1" -o -z "$2" -o "$showhelp" ]; then - sed '/#ENDCOMMENT/,$d' <$0 >&2 - exit 1 -fi - -shift `expr $OPTIND - 1` - -pfb="$1" -afm=`basename "$1" .pfb`.afm -egg=$2 - -# Perform some sanity checks on input parameters. - -if [ -f "$pfb" ]; then - basepfb=`basename "$pfb" .pfb` - basePFB=`basename "$pfb" .PFB` - base=`basename "$pfb"` - if [ "$basepfb" = "$base" -a "$basePFB" = "$base" ]; then - echo "$pfb should end in .pfb or .PFB" - exit 1 - fi -else - echo "$pfb does not exist." - exit 1 -fi - -if [ ! -f "$afm" ]; then - echo "$afm does not exist." - exit 1 -fi - -if [ `basename $egg .egg` = `basename $egg` ]; then - echo "$egg should end in .egg" - exit 1 -fi - -fontname=`basename $egg .egg` -shift 2 - -if [ "x$1" = "x--" ]; then - shift -fi - -# Create a temporary PFB and AFM filename in case the source filename -# has bad characters (like spaces). -temppfb=$fontname.pfb -tempafm=$fontname.afm -if [ $temppfb != "$pfb" ]; then - echo ln -s \"$pfb\" $temppfb - if ln -s "$pfb" $temppfb; then - status=0 - else - echo Cannot create $temppfb - exit 1 - fi - echo ln -s \"$afm\" $tempafm - if ln -s "$afm" $tempafm; then - status=0 - else - echo Cannot create $tempafm - exit 1 - fi -fi - -status=0 -echo afm2tfm $tempafm -if afm2tfm $tempafm; then - echo ps2pk -X$dpi -P$pointsize \"$fontname\" - if ps2pk -X$dpi -P$pointsize "$fontname" >/dev/null; then - echo egg-mkfont $* -o \"$egg\" \"$fontname$pointsize.${dpi}pk\" - egg-mkfont $* -o "$egg" "$fontname$pointsize.${dpi}pk" - status=$? - else - echo Error running ps2pk. - status=1 - fi -else - echo Error running afm2tfm. - status=1 -fi - -rm -f "$fontname.tfm" "$fontname$pointsize.${dpi}pk" -if [ $temppfb != "$pfb" ]; then - rm -f $temppfb -fi -if [ $tempafm != "$afm" ]; then - rm -f $tempafm -fi - -if [ $status != 0 ]; then - echo "" - echo "***************************" - echo "*** Cannot convert $pfb ***" - echo "***************************" - echo "" -fi - -exit $status diff --git a/pandatool/src/egg-mkfont/pkFontFile.cxx b/pandatool/src/egg-mkfont/pkFontFile.cxx deleted file mode 100644 index d00a553e49..0000000000 --- a/pandatool/src/egg-mkfont/pkFontFile.cxx +++ /dev/null @@ -1,916 +0,0 @@ -// Filename: pkFontFile.cxx -// Created by: drose (18Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#include "pkFontFile.h" -#include "charBitmap.h" - -/******************************************************************** - -I found the following in a source file for pftype called pftype.web. -It's some nutty TeX-based Pascal program, and the documentation is a -little hard to read because of the embedded TeX formatting controls. -But it describes quite thoroughly the format of the pk file. - -********************************************************************* - -@* Packed file format. -The packed file format is a compact representation of the data contained in a -\.{GF} file. The information content is the same, but packed (\.{PK}) files -are almost always less than half the size of their \.{GF} counterparts. They -are also easier to convert into a raster representation because they do not -have a profusion of \\{paint}, \\{skip}, and \\{new\_row} commands to be -separately interpreted. In addition, the \.{PK} format expressedly forbids -\&{special} commands within a character. The minimum bounding box for each -character is explicit in the format, and does not need to be scanned for as in -the \.{GF} format. Finally, the width and escapement values are combined with -the raster information into character ``packets'', making it simpler in many -cases to process a character. - -A \.{PK} file is organized as a stream of 8-bit bytes. At times, these bytes -might be split into 4-bit nybbles or single bits, or combined into multiple -byte parameters. When bytes are split into smaller pieces, the `first' piece -is always the most significant of the byte. For instance, the first bit of -a byte is the bit with value 128; the first nybble can be found by dividing -a byte by 16. Similarly, when bytes are combined into multiple byte -parameters, the first byte is the most significant of the parameter. If the -parameter is signed, it is represented by two's-complement notation. - -The set of possible eight-bit values is separated into two sets, those that -introduce a character definition, and those that do not. The values that -introduce a character definition range from 0 to 239; byte values -above 239 are interpreted as commands. Bytes that introduce character -definitions are called flag bytes, and various fields within the byte indicate -various things about how the character definition is encoded. Command bytes -have zero or more parameters, and can never appear within a character -definition or between parameters of another command, where they would be -interpeted as data. - -A \.{PK} file consists of a preamble, followed by a sequence of one or more -character definitions, followed by a postamble. The preamble command must -be the first byte in the file, followed immediately by its parameters. -Any number of character definitions may follow, and any command but the -preamble command and the postamble command may occur between character -definitions. The very last command in the file must be the postamble. - -@ The packed file format is intended to be easy to read and interpret by -device drivers. The small size of the file reduces the input/output overhead -each time a font is loaded. For those drivers that load and save each font -file into memory, the small size also helps reduce the memory requirements. -The length of each character packet is specified, allowing the character raster -data to be loaded into memory by simply counting bytes, rather than -interpreting each command; then, each character can be interpreted on a demand -basis. This also makes it possible for a driver to skip a particular -character quickly if it knows that the character is unused. - -@ First, the command bytes will be presented; then the format of the -character definitions will be defined. Eight of the possible sixteen -commands (values 240 through 255) are currently defined; the others are -reserved for future extensions. The commands are listed below. Each command -is specified by its symbolic name (e.g., \\{pk\_no\_op}), its opcode byte, -and any parameters. The parameters are followed by a bracketed number -telling how many bytes they occupy, with the number preceded by a plus sign if -it is a signed quantity. (Four byte quantities are always signed, however.) - -\yskip\hang|pk_xxx1| 240 |k[1]| |x[k]|. This command is undefined in general; -it functions as a $(k+2)$-byte \\{no\_op} unless special \.{PK}-reading -programs are being used. \MF\ generates \\{xxx} commands when encountering -a \&{special} string. It is recommended that |x| be a string having the form -of a keyword followed by possible parameters relevant to that keyword. - -\yskip\hang\\{pk\_xxx2} 241 |k[2]| |x[k]|. Like |pk_xxx1|, but |0<=k<65536|. - -\yskip\hang\\{pk\_xxx3} 242 |k[3]| |x[k]|. Like |pk_xxx1|, but -|0<=k<@t$2^{24}$@>|. \MF\ uses this when sending a \&{special} string whose -length exceeds~255. - -\yskip\hang\\{pk\_xxx4} 243 |k[4]| |x[k]|. Like |pk_xxx1|, but |k| can be -ridiculously large; |k| musn't be negative. - -\yskip\hang|pk_yyy| 244 |y[4]|. This command is undefined in general; it -functions as a five-byte \\{no\_op} unless special \.{PK} reading programs -are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a result of -\&{numspecial} commands; the intent is to provide numeric parameters to -\\{xxx} commands that immediately precede. - -\yskip\hang|pk_post| 245. Beginning of the postamble. This command is -followed by enough |pk_no_op| commands to make the file a multiple -of four bytes long. Zero through three bytes are usual, but any number -is allowed. -This should make the file easy to read on machines that pack four bytes to -a word. - -\yskip\hang|pk_no_op| 246. No operation, do nothing. Any number of -|pk_no_op|'s may appear between \.{PK} commands, but a |pk_no_op| cannot be -inserted between a command and its parameters, between two parameters, or -inside a character definition. - -\yskip\hang|pk_pre| 247 |i[1]| |k[1]| |x[k]| |ds[4]| |cs[4]| |hppp[4]| -|vppp[4]|. Preamble command. Here, |i| is the identification byte of the -file, currently equal to 89. The string |x| is merely a comment, usually -indicating the source of the \.{PK} file. The parameters |ds| and |cs| are -the design size of the file in $1/2^{20}$ points, and the checksum of the -file, respectively. The checksum should match the \.{TFM} file and the -\.{GF} files for this font. Parameters |hppp| and |vppp| are the ratios -of pixels per point, horizontally and vertically, multiplied by $2^{16}$; they -can be used to correlate the font with specific device resolutions, -magnifications, and ``at sizes''. Usually, the name of the \.{PK} file is -formed by concatenating the font name (e.g., cmr10) with the resolution at -which the font is prepared in pixels per inch multiplied by the magnification -factor, and the letters \.{pk}. For instance, cmr10 at 300 dots per inch -should be named \.{cmr10.300pk}; at one thousand dots per inch and magstephalf, -it should be named \.{cmr10.1095pk}. - -@ We put a few of the above opcodes into definitions for symbolic use by -this program. - -@d pk_id = 89 {the version of \.{PK} file described} -@d pk_xxx1 = 240 {\&{special} commands} -@d pk_yyy = 244 {\&{numspecial} commands} -@d pk_post = 245 {postamble} -@d pk_no_op = 246 {no operation} -@d pk_pre = 247 {preamble} -@d pk_undefined == 248, 249, 250, 251, 252, 253, 254, 255 - -@ The \.{PK} format has two conflicting goals: to pack character raster and -size information as compactly as possible, while retaining ease of translation -into raster and other forms. A suitable compromise was found in the use of -run-encoding of the raster information. Instead of packing the individual -bits of the character, we instead count the number of consecutive `black' or -`white' pixels in a horizontal raster row, and then encode this number. Run -counts are found for each row from left to right, traversing rows from the -top to bottom. This is essentially the way the \.{GF} format works. -Instead of presenting each row individually, however, we concatenate all -of the horizontal raster rows into one long string of pixels, and encode this -row. With knowledge of the width of the bit-map, the original character glyph -can easily be reconstructed. In addition, we do not need special commands to -mark the end of one row and the beginning of the next. - -Next, we place the burden of finding the minimum bounding box on the part -of the font generator, since the characters will usually be used much more -often than they are generated. The minimum bounding box is the smallest -rectangle that encloses all `black' pixels of a character. We also -eliminate the need for a special end of character marker, by supplying -exactly as many bits as are required to fill the minimum bounding box, from -which the end of the character is implicit. - -Let us next consider the distribution of the run counts. Analysis of several -dozen pixel files at 300 dots per inch yields a distribution peaking at four, -falling off slowly until ten, then a bit more steeply until twenty, and then -asymptotically approaching the horizontal. Thus, the great majority of our -run counts will fit in a four-bit nybble. The eight-bit byte is attractive for -our run-counts, as it is the standard on many systems; however, the wasted four -bits in the majority of cases seem a high price to pay. Another possibility -is to use a Huffman-type encoding scheme with a variable number of bits for -each run-count; this was rejected because of the overhead in fetching and -examining individual bits in the file. Thus, the character raster definitions -in the \.{PK} file format are based on the four-bit nybble. - -@ An analysis of typical pixel files yielded another interesting statistic: -Fully 37\char`\%\ -of the raster rows were duplicates of the previous row. Thus, the \.{PK} -format allows the specification of repeat counts, which indicate how many times -a horizontal raster row is to be repeated. These repeated rows are taken out -of the character glyph before individual rows are concatenated into the long -string of pixels. - -For elegance, we disallow a run count of zero. The case of a null raster -description should be gleaned from the character width and height being equal -to zero, and no raster data should be read. No other zero counts are ever -necessary. Also, in the absence of repeat counts, the repeat value is set to -be zero (only the original row is sent.) If a repeat count is seen, it takes -effect on the current row. The current row is defined as the row on which the -first pixel of the next run count will lie. The repeat count is set back to -zero when the last pixel in the current row is seen, and the row is sent out. - -This poses a problem for entirely black and entirely white rows, however. Let -us say that the current row ends with four white pixels, and then we have five -entirely empty rows, followed by a black pixel at the beginning of the next -row, and the character width is ten pixels. We would like to use a repeat -count, but there is no legal place to put it. If we put it before the white -run count, it will apply to the current row. If we put it after, it applies -to the row with the black pixel at the beginning. Thus, entirely white or -entirely black repeated rows are always packed as large run counts (in this -case, a white run count of 54) rather than repeat counts. - -@ Now we turn our attention to the actual packing of the run counts and -repeat counts into nybbles. There are only sixteen possible nybble values. -We need to indicate run counts and repeat counts. Since the run counts are -much more common, we will devote the majority of the nybble values to them. -We therefore indicate a repeat count by a nybble of 14 followed by a packed -number, where a packed number will be explained later. Since the repeat -count value of one is so common, we indicate a repeat one command by a single -nybble of 15. A 14 followed by the packed number 1 is still legal for a -repeat one count. The run counts are coded directly as packed -numbers. - -For packed numbers, therefore, we have the nybble values 0 through 13. We -need to represent the positive integers up to, say, $2^{31}-1$. We would -like the more common smaller numbers to take only one or two nybbles, and -the infrequent large numbers to take three or more. We could therefore -allocate one nybble value to indicate a large run count taking three or more -nybbles. We do this with the value 0. - -@ We are left with the values 1 through 13. We can allocate some of these, say -|dyn_f|, to be one-nybble run counts. -These will work for the run counts |1..dyn_f|. For subsequent run -counts, we will use a nybble greater than |dyn_f|, followed by a second nybble, -whose value can run from 0 through 15. Thus, the two-nybble values will -run from |dyn_f+1..(13-dyn_f)*16+dyn_f|. We have our definition of large run -count values now, being all counts greater than |(13-dyn_f)*16+dyn_f|. - -We can analyze our several dozen pixel files and determine an optimal value of -|dyn_f|, and use this value for all of the characters. Unfortunately, values -of |dyn_f| that pack small characters well tend to pack the large characters -poorly, and values that pack large characters well are not efficient for the -smaller characters. Thus, we choose the optimal |dyn_f| on a character basis, -picking the value that will pack each individual character in the smallest -number of nybbles. Legal values of |dyn_f| run from 0 (with no one-nybble run -counts) to 13 (with no two-nybble run counts). - -@ Our only remaining task in the coding of packed numbers is the large run -counts. We use a scheme suggested by D.~E.~Knuth -@^Knuth, Donald Ervin@> -that simply and elegantly represents arbitrarily large values. The -general scheme to represent an integer |i| is to write its hexadecimal -representation, with leading zeros removed. Then we count the number of -digits, and prepend one less than that many zeros before the hexadecimal -representation. Thus, the values from one to fifteen occupy one nybble; -the values sixteen through 255 occupy three, the values 256 through 4095 -require five, etc. - -For our purposes, however, we have already represented the numbers one -through |(13-dyn_f)*16+dyn_f|. In addition, the one-nybble values have -already been taken by our other commands, which means that only the values -from sixteen up are available to us for long run counts. Thus, we simply -normalize our long run counts, by subtracting |(13-dyn_f)*16+dyn_f+1| and -adding 16, and then we represent the result according to the scheme above. - -@ The final algorithm for decoding the run counts based on the above scheme -looks like this, assuming that a procedure called \\{pk\_nyb} is available -to get the next nybble from the file, and assuming that the global -|repeat_count| indicates whether a row needs to be repeated. Note that this -routine is recursive, but since a repeat count can never directly follow -another repeat count, it can only be recursive to one level. - -@= -function pk_packed_num : integer ; -var i, @!j : integer ; -begin - i := get_nyb ; - if i = 0 then begin - repeat j := get_nyb ; incr(i) ; until j <> 0 ; - while i > 0 do begin j := j * 16 + get_nyb ; decr(i) ; end ; - pk_packed_num := j - 15 + (13-dyn_f)*16 + dyn_f ; - end else if i <= dyn_f then - pk_packed_num := i - else if i < 14 then - pk_packed_num := (i-dyn_f-1)*16+get_nyb+dyn_f+1 - else begin - if repeat_count <> 0 then abort('Second repeat count for this row!') ; -@.Second repeat count...@> - repeat_count := 1; {prevent recursion more than one level} - if i = 14 then repeat_count := pk_packed_num; - send_out(true, repeat_count) ; - pk_packed_num := pk_packed_num ; - end ; -end ; - -@ For low resolution fonts, or characters with `gray' areas, run encoding can -often make the character many times larger. Therefore, for those characters -that cannot be encoded efficiently with run counts, the \.{PK} format allows -bit-mapping of the characters. This is indicated by a |dyn_f| value of -14. The bits are packed tightly, by concatenating all of the horizontal raster -rows into one long string, and then packing this string eight bits to a byte. -The number of bytes required can be calculated by |(width*height+7) div 8|. -This format should only be used when packing the character by run counts takes -more bytes than this, although, of course, it is legal for any character. -Any extra bits in the last byte should be set to zero. - -@ At this point, we are ready to introduce the format for a character -descriptor. It consists of three parts: a flag byte, a character preamble, -and the raster data. The most significant four bits of the flag byte -yield the |dyn_f| value for that character. (Notice that only values of -0 through 14 are legal for |dyn_f|, with 14 indicating a bit mapped character; -thus, the flag bytes do not conflict with the command bytes, whose upper nybble -is always 15.) The next bit (with weight 8) indicates whether the first run -count is a black count or a white count, with a one indicating a black count. -For bit-mapped characters, this bit should be set to a zero. The next bit -(with weight 4) indicates whether certain later parameters (referred to as size -parameters) are given in one-byte or two-byte quantities, with a one indicating -that they are in two-byte quantities. The last two bits are concatenated on to -the beginning of the packet-length parameter in the character preamble, -which will be explained below. - -However, if the last three bits of the flag byte are all set (normally -indicating that the size parameters are two-byte values and that a 3 should be -prepended to the length parameter), then a long format of the character -preamble should be used instead of one of the short forms. - -Therefore, there are three formats for the character preamble; the one that -is used depends on the least significant three bits of the flag byte. If the -least significant three bits are in the range zero through three, the short -format is used. If they are in the range four through six, the extended short -format is used. Otherwise, if the least significant bits are all set, then -the long form of the character preamble is used. The preamble formats are -explained below. - -\yskip\hang Short form: |flag[1]| |pl[1]| |cc[1]| |tfm[3]| |dm[1]| |w[1]| -|h[1]| |hoff[+1]| |voff[+1]|. -If this format of the character preamble is used, the above -parameters must all fit in the indicated number of bytes, signed or unsigned -as indicated. Almost all of the standard \TeX\ font characters fit; the few -exceptions are fonts such as \.{cminch}. - -\yskip\hang Extended short form: |flag[1]| |pl[2]| |cc[1]| |tfm[3]| |dm[2]| -|w[2]| |h[2]| |hoff[+2]| |voff[+2]|. Larger characters use this extended -format. - -\yskip\hang Long form: |flag[1]| |pl[4]| |cc[4]| |tfm[4]| |dx[4]| |dy[4]| -|w[4]| |h[4]| |hoff[4]| |voff[4]|. This is the general format that -allows all of the -parameters of the \.{GF} file format, including vertical escapement. -\vskip\baselineskip -The |flag| parameter is the flag byte. The parameter |pl| (packet length) -contains the offset -of the byte following this character descriptor, with respect to the beginning -of the |tfm| width parameter. This is given so a \.{PK} reading program can, -once it has read the flag byte, packet length, and character code (|cc|), skip -over the character by simply reading this many more bytes. For the two short -forms of the character preamble, the last two bits of the flag byte should be -considered the two most-significant bits of the packet length. For the short -format, the true packet length might be calculated as |(flag mod 4)*256+pl|; -for the short extended format, it might be calculated as -|(flag mod 4)*65536+pl|. - -The |w| parameter is the width and the |h| parameter is the height in pixels -of the minimum bounding box. The |dx| and |dy| parameters are the horizontal -and vertical escapements, respectively. In the short formats, |dy| is assumed -to be zero and |dm| is |dx| but in pixels; -in the long format, |dx| and |dy| are both -in pixels multiplied by $2^{16}$. The |hoff| is the horizontal offset from the -upper left pixel to the reference pixel; the |voff| is the vertical offset. -They are both given in pixels, with right and down being positive. The -reference pixel is the pixel that occupies the unit square in \MF; the -\MF\ reference point is the lower left hand corner of this pixel. (See the -example below.) - -@ \TeX\ requires all characters that have the same character codes -modulo 256 to have also the same |tfm| widths and escapement values. The \.{PK} -format does not itself make this a requirement, but in order for the font to -work correctly with the \TeX\ software, this constraint should be observed. -(The standard version of \TeX\ cannot output character codes greater -than 255, but extended versions do exist.) - -Following the character preamble is the raster information for the -character, packed by run counts or by bits, as indicated by the flag byte. -If the character is packed by run counts and the required number of nybbles -is odd, then the last byte of the raster description should have a zero -for its least significant nybble. - -@ As an illustration of the \.{PK} format, the character \char4\ from the font -amr10 at 300 dots per inch will be encoded. This character was chosen -because it illustrates some -of the borderline cases. The raster for the character looks like this (the -row numbers are chosen for convenience, and are not \MF's row numbers.) - -\vskip\baselineskip -{\def\smbox{\vrule height 7pt width 7pt depth 0pt \hskip 3pt}% -\catcode`\*=\active \let*=\smbox -\centerline{\vbox{\baselineskip=10pt -\halign{\hfil#\quad&&\hfil#\hfil\cr -0& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -1& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -2& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -3& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -4& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -5& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -6& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -7\cr -8\cr -9& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -10& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -11& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -12& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr -13& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr -14& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr -15& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr -16& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -17& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -18& & & & &*&*& & & & & & & & & & & & &*&*& & \cr -19\cr -20\cr -21\cr -22& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -23& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -24& & &*&*& & & & & & & & & & & & & & & & &*&*\cr -25& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -26& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -27& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -28&+& &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr -&\hphantom{*}&\hphantom{*}\cr -}}}} -The width of the minimum bounding box for this character is 20; its height -is 29. The `+' represents the reference pixel; notice how it lies outside the -minimum bounding box. The |hoff| value is $-2$, and the |voff| is~28. - -The first task is to calculate the run counts and repeat counts. The repeat -counts are placed at the first transition (black to white or white to black) -in a row, and are enclosed in brackets. White counts are enclosed in -parentheses. It is relatively easy to generate the counts list: -\vskip\baselineskip -\centerline{82 [2] (16) 2 (42) [2] 2 (12) 2 (4) [3]} -\centerline{16 (4) [2] 2 (12) 2 (62) [2] 2 (16) 82} -\vskip\baselineskip -Note that any duplicated rows that are not all white or all black are removed -before the run counts are calculated. The rows thus removed are rows 5, 6, -10, 11, 13, 14, 15, 17, 18, 23, and 24. - -@ The next step in the encoding of this character is to calculate the optimal -value of |dyn_f|. The details of how this calculation is done are not -important here; suffice it to say that there is a simple algorithm that can -determine the best value of |dyn_f| in one pass over the count list. For this -character, the optimal value turns out to be 8 (atypically low). Thus, all -count values less than or equal to 8 are packed in one nybble; those from -nine to $(13-8)*16+8$ or 88 are packed in two nybbles. The run encoded values -now become (in hex, separated according to the above list): -\vskip\baselineskip -\centerline{\tt D9 E2 97 2 B1 E2 2 93 2 4 E3} -\centerline{\tt 97 4 E2 2 93 2 C5 E2 2 97 D9} -\vskip\baselineskip\noindent -which comes to 36 nybbles, or 18 bytes. This is shorter than the 73 bytes -required for the bit map, so we use the run count packing. - -@ The short form of the character preamble is used because all of the -parameters fit in their respective lengths. The packet length is therefore -18 bytes for the raster, plus -eight bytes for the character preamble parameters following the character -code, or 26. The |tfm| width for this character is 640796, or {\tt 9C71C} in -hexadecimal. The horizontal escapement is 25 pixels. The flag byte is -88 hex, indicating the short preamble, the black first count, and the -|dyn_f| value of 8. The final total character packet, in hexadecimal, is: -\vskip\baselineskip -$$\vbox{\halign{\hfil #\quad&&{\tt #\ }\cr -Flag byte&88\cr -Packet length&1A\cr -Character code&04\cr -|tfm| width&09&C7&1C\cr -Horizontal escapement (pixels)&19\cr -Width of bit map&14\cr -Height of bit map&1D\cr -Horizontal offset (signed)&FE\cr -Vertical offset&1C\cr -Raster data&D9&E2&97\cr -&2B&1E&22\cr -&93&24&E3\cr -&97&4E&22\cr -&93&2C&5E\cr -&22&97&D9\cr}}$$ -********************************************************************/ - -#define PK_XXX1 240 -#define PK_XXX2 241 -#define PK_XXX3 242 -#define PK_XXX4 243 -#define PK_YYY 244 -#define PK_POST 245 -#define PK_NO_OP 246 -#define PK_PRE 247 - - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -PkFontFile:: -PkFontFile() { -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::read -// Access: Public, Virtual -// Description: Attempts to read the font from the indicated file. -// Returns true if successful, false if there is an -// error. -//////////////////////////////////////////////////////////////////// -bool PkFontFile:: -read(const Filename &filename, bool extract_all, const string &extract_only) { - Filename input_filename = filename; - - input_filename.set_binary(); - ifstream pk_file; - if (!input_filename.open_read(pk_file)) { - return false; - } - - // First, read the whole thing into a memory buffer, so we can - // easily access bytes at random locations in the file. - unsigned char c = pk_file.get(); - while (pk_file && !pk_file.eof()) { - _pk.push_back(c); - c = pk_file.get(); - } - - _p = 0; - _high = true; - _post = false; - _post_warning = false; - - _extract_all = extract_all; - _extract_only = extract_only; - - return read_pk(); -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::fetch_nibble -// Access: Private -// Description: Returns the next 4-bit nibble from the pk stream. -//////////////////////////////////////////////////////////////////// -unsigned int PkFontFile:: -fetch_nibble() { - assert(_p < (int)_pk.size()); - if (_high) { - _high = false; - return _pk[_p] >> 4; - } else { - _high = true; - return _pk[_p++] & 0xf; - } -} - - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::fetch_packed_int -// Access: Private -// Description: Returns the next packed integer from the pk stream. -//////////////////////////////////////////////////////////////////// -unsigned int PkFontFile:: -fetch_packed_int() { - int i = fetch_nibble(); - if (i == 0) { - int j; - do { - j = fetch_nibble(); - i++; - } while (j == 0); - while (i > 0) { - j = (j << 4) | fetch_nibble(); - i--; - } - return j - 15 + (13 - _dyn_f)*16 + _dyn_f; - - } else if (i <= _dyn_f) { - return i; - - } else if (i < 14) { - return (i - _dyn_f - 1)*16 + fetch_nibble() + _dyn_f + 1; - - } else { - _repeat_count = 1; - if (i == 14) { - _repeat_count = fetch_packed_int(); - } - // nout << "[" << _repeat_count << "]"; - return fetch_packed_int(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::fetch_byte -// Access: Private -// Description: Returns the next 8-bit unsigned byte from the pk -// stream. -//////////////////////////////////////////////////////////////////// -unsigned int PkFontFile:: -fetch_byte() { - assert(_high); - assert(_p < (int)_pk.size()); - return _pk[_p++]; -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::fetch_int -// Access: Private -// Description: Returns the next n-byte unsigned int from -// the pk stream. -//////////////////////////////////////////////////////////////////// -unsigned int PkFontFile:: -fetch_int(int n) { - assert(_high); - - unsigned int result = 0; - for (int i = 0; i < n; i++) { - assert(_p < (int)_pk.size()); - result = (result << 8) | _pk[_p]; - _p++; - } - - return result; -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::fetch_signed_int -// Access: Private -// Description: Returns the next n-byte signed int from -// the pk stream. -//////////////////////////////////////////////////////////////////// -int PkFontFile:: -fetch_signed_int(int n) { - assert(_high); - - assert(_p < (int)_pk.size()); - int result = (signed char)_pk[_p]; - _p++; - for (int i = 1; i < n; i++) { - assert(_p < (int)_pk.size()); - result = (result << 8) | _pk[_p]; - _p++; - } - - return result; -} - - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::do_character -// Access: Private -// Description: Reads a single character from the pk file and -// processes it. Returns true if successful, false if -// something bad happened. -//////////////////////////////////////////////////////////////////// -bool PkFontFile:: -do_character(int flag_byte) { - // int start_p = _p - 1; - _dyn_f = (flag_byte >> 4); - bool first_black = ((flag_byte & 0x8) != 0); - int bsize = (flag_byte & 0x4) ? 2 : 1; - int prepend_length = (flag_byte & 0x3); - - bool use_long_form = ((flag_byte & 0x7) == 0x7); - - unsigned int pl, cc, itfm, w, h; - int hoff, voff; - unsigned int idx = 0; - unsigned int idy = 0; - int next_p; - - if (use_long_form) { - pl = fetch_int(); - cc = fetch_int(); - next_p = _p + pl; - itfm = fetch_int(); - idx = fetch_int(); - idy = fetch_int(); - w = fetch_int(); - h = fetch_int(); - hoff = fetch_signed_int(); - voff = fetch_signed_int(); - } else { - pl = fetch_int(bsize) | (prepend_length << bsize*8); - cc = fetch_byte(); - next_p = _p + pl; - itfm = fetch_int(3); - idx = fetch_int(bsize) << 16; - w = fetch_int(bsize); - h = fetch_int(bsize); - hoff = fetch_signed_int(bsize); - voff = fetch_signed_int(bsize); - } - - // double tfm = (double)itfm / (double)(1 << 24); - double dx = (double)idx / (double)(1 << 16); - double dy = (double)idy / (double)(1 << 16); - // double di_width = tfm * _ppu * _hppp / _vppp; - - if (_extract_all || - ((cc >= 33 && cc <= 127) && - (_extract_only.empty() || _extract_only.find((char)cc) != string::npos))) { - nout << " " << cc; - - CharBitmap *bm = new CharBitmap(cc, w, h, hoff, voff, dx, dy); - - if (_dyn_f == 14) { - // A bitmapped character: this character has the actual w x h - // bits stored directly in the pk file. This kind of character - // is quite rare, but it's come up at least once, so the code - // has been seen to work. - unsigned int bit = 0; - unsigned int byte = 0; - for (unsigned int y = 0; y < h; y++) { - for (unsigned int x = 0; x < w; x++) { - if (bit == 0) { - bit = 0x80; - byte = fetch_byte(); - } - bm->_block[y][x] = ((byte & bit)!=0); - bit >>= 1; - } - } - - } else { - // A normal, rle character. This character has sequences of - // black and white runs stored in the pk file. Most characters - // will be stored this way. - bool black = first_black; - _repeat_count = 0; - - int count = fetch_packed_int(); - while (bm->paint(black, count, _repeat_count)) { - /* - if (black) { - nout << count; - } else { - nout << "(" << count << ")"; - } - */ - black = !black; - count = fetch_packed_int(); - } - // nout << "\n"; - } - - _chars.push_back(bm); - - /* - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - nout << (bm->_block[y][x] ? ' ' : '*'); - } - nout << "\n"; - } - */ - - if (!_high) { - _p++; - _high = true; - } - - if (_p != next_p) { - nout << "Expected p == " << next_p << " got " << _p << "\n"; - } - - } else { - nout << " (" << cc << ")"; - } - - _p = next_p; - return true; -} - - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::do_xxx -// Access: Private -// Description: The xxx1 .. xxx4 series of commands specify an -// embedded comment or some such silliness in the pk -// file that must be skipped. -//////////////////////////////////////////////////////////////////// -void PkFontFile:: -do_xxx(int num_bytes) { - _p += fetch_int(num_bytes); -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::do_yyy -// Access: Private -// Description: The yyy command is an encoded number which might have -// meaning to a preceding xxx block, but means nothing -// to us. -//////////////////////////////////////////////////////////////////// -void PkFontFile:: -do_yyy() { - _p += 4; -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::do_post -// Access: Private -// Description: The beginning of the postamble. -//////////////////////////////////////////////////////////////////// -void PkFontFile:: -do_post() { - _post = true; -} - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::do_pre -// Access: Private -// Description: The preamble. -//////////////////////////////////////////////////////////////////// -void PkFontFile:: -do_pre() { - int id = fetch_byte(); - if (id != 89) { - nout << "Warning: PK file had an unexpected ID, " << id << "\n"; - } - - int comment_len = fetch_byte(); - - assert(_p + comment_len <= (int)_pk.size()); - nout.write((const char *)&_pk[_p], comment_len); - nout << "\n"; - _p += comment_len; - - int ds = fetch_int(); - fetch_int(); // cs - int hppp = fetch_int(); - int vppp = fetch_int(); - - _ds = (double)ds / (double)(1 << 20); - _hppp = (double)hppp / (double)(1 << 16); - _vppp = (double)vppp / (double)(1 << 16); - - nout << "Font size is " << get_ds() << " points, rasterized at " - << get_dpi() << " DPI.\n"; -} - - -//////////////////////////////////////////////////////////////////// -// Function: PkFontFile::read_pk -// Access: Private -// Description: -//////////////////////////////////////////////////////////////////// -bool PkFontFile:: -read_pk() { - if (_p >= (int)_pk.size()) { - nout << "PK file is empty.\n"; - return false; - } - unsigned int cmd = fetch_byte(); - if (cmd != PK_PRE) { - nout << "Not a PK file.\n"; - return false; - } - do_pre(); - - nout << "Characters:"; - - while (_p < (int)_pk.size()) { - unsigned int cmd = fetch_byte(); - if (_post && !_post_warning && cmd != PK_NO_OP) { - _post_warning = true; - nout << "\nWarning: postamble was not the last command.\n"; - } - if (cmd < 240) { - if (!do_character(cmd)) { - return true; - } - } else { - switch (cmd) { - case PK_XXX1: - do_xxx(1); - break; - - case PK_XXX2: - do_xxx(2); - break; - - case PK_XXX3: - do_xxx(3); - break; - - case PK_XXX4: - do_xxx(4); - break; - - case PK_YYY: - do_yyy(); - break; - - case PK_POST: - do_post(); - break; - - case PK_NO_OP: - break; - - default: - nout << "\nUnexpected command " << cmd << " encountered in PK file\n"; - return false; - } - } - } - nout << "\n"; - - if (!_post) { - nout << "Warning: did not encounter postamble.\n"; - } - - return true; -} diff --git a/pandatool/src/egg-mkfont/pkFontFile.h b/pandatool/src/egg-mkfont/pkFontFile.h deleted file mode 100644 index 64a83752c6..0000000000 --- a/pandatool/src/egg-mkfont/pkFontFile.h +++ /dev/null @@ -1,64 +0,0 @@ -// Filename: pkFontFile.h -// Created by: drose (18Feb01) -// -//////////////////////////////////////////////////////////////////// -// -// PANDA 3D SOFTWARE -// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved -// -// All use of this software is subject to the terms of the Panda 3d -// Software license. You should have received a copy of this license -// along with this source code; you will also find a current copy of -// the license at http://www.panda3d.org/license.txt . -// -// To contact the maintainers of this program write to -// panda3d@yahoogroups.com . -// -//////////////////////////////////////////////////////////////////// - -#ifndef PKFONTFILE_H -#define PKFONTFILE_H - -#include - -#include "fontFile.h" - -//////////////////////////////////////////////////////////////////// -// Class : PkFontFile -// Description : A specialization on FontFile for reading TeX-style -// .pk fonts. -//////////////////////////////////////////////////////////////////// -class PkFontFile : public FontFile { -public: - PkFontFile(); - - virtual bool read(const Filename &filename, - bool extract_all, const string &extract_only); - -private: - unsigned int fetch_nibble(); - unsigned int fetch_packed_int(); - unsigned int fetch_byte(); - unsigned int fetch_int(int n = 4); - int fetch_signed_int(int n = 4); - bool do_character(int flag_byte); - void do_xxx(int num_bytes); - void do_yyy(); - void do_post(); - void do_pre(); - bool read_pk(); - - bool _post; - bool _post_warning; - int _p; - bool _high; - int _dyn_f; - int _repeat_count; - - bool _extract_all; - string _extract_only; - - pvector _pk; -}; - -#endif diff --git a/pandatool/src/egg-mkfont/rangeDescription.I b/pandatool/src/egg-mkfont/rangeDescription.I new file mode 100644 index 0000000000..e33b13a471 --- /dev/null +++ b/pandatool/src/egg-mkfont/rangeDescription.I @@ -0,0 +1,78 @@ +// Filename: rangeDescription.I +// Created by: drose (07Sep03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::add_singleton +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void RangeDescription:: +add_singleton(int code) { + _range_list.push_back(Range(code)); +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::add_range +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void RangeDescription:: +add_range(int from_code, int to_code) { + _range_list.push_back(Range(from_code, to_code)); +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::is_empty +// Access: Public +// Description: Returns true if there are no codes described in the +// range. +//////////////////////////////////////////////////////////////////// +INLINE bool RangeDescription:: +is_empty() const { + return _range_list.empty(); +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::Range::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RangeDescription::Range:: +Range(int code) : + _from_code(code), + _to_code(code) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::Range::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RangeDescription::Range:: +Range(int from_code, int to_code) : + _from_code(from_code), + _to_code(to_code) +{ +} + +INLINE ostream &operator << (ostream &out, const RangeDescription &range) { + range.output(out); + return out; +} diff --git a/pandatool/src/egg-mkfont/rangeDescription.cxx b/pandatool/src/egg-mkfont/rangeDescription.cxx new file mode 100644 index 0000000000..1da3b95a20 --- /dev/null +++ b/pandatool/src/egg-mkfont/rangeDescription.cxx @@ -0,0 +1,199 @@ +// Filename: rangeDescription.cxx +// Created by: drose (07Sep03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "rangeDescription.h" +#include "string_utils.h" +#include "notify.h" + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +RangeDescription:: +RangeDescription() { +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::parse_parameter +// Access: Public +// Description: 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. Returns true if +// the parameter is parsed correctly, false otherwise. +//////////////////////////////////////////////////////////////////// +bool RangeDescription:: +parse_parameter(const string ¶m) { + // First, go through and separate the string by commas. We have to + // do this by hand instead of calling tokenize(), because we also + // have to scan for square brackets, which may contain nested + // commas. + size_t p = 0; + while (p < param.length()) { + size_t q = param.find_first_of("[,", p); + if (q == string::npos) { + return parse_word(trim(param.substr(p))); + } + if (!parse_word(trim(param.substr(p, q - p)))) { + return false; + } + + if (param[q] == '[') { + // A square bracket means we must search for the matching square + // bracket. However, a right bracket immediately after the left + // bracket doesn't count; we start the scan after that. + p = param.find("]", q + 2); + if ( p == string::npos) { + nout << "Unclosed open bracket.\n"; + return false; + } + if (!parse_bracket(param.substr(q + 1, p - q - 1))) { + return false; + } + p = p + 1; + + } else { + // Otherwise, if the separator was just a comma, the next + // character begins the next word. + p = q + 1; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void RangeDescription:: +output(ostream &out) const { + bool first_time = true; + RangeList::const_iterator ri; + for (ri = _range_list.begin(); ri != _range_list.end(); ++ri) { + const Range &range = (*ri); + if (!first_time) { + out << ","; + } + first_time = false; + if (range._from_code == range._to_code) { + out << range._from_code; + } else { + out << range._from_code << "-" << range._to_code; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::parse_word +// Access: Private +// Description: Parses a single "word", i.e. the text delimited by +// commas, that might be listed on the command line. +// This is generally either the empty string, a single +// number, or a pair of numbers separated by a hyphen. +//////////////////////////////////////////////////////////////////// +bool RangeDescription:: +parse_word(const string &word) { + if (word.empty()) { + return true; + } + + // It's not empty, so see if it includes a hyphen. + size_t hyphen = word.find('-'); + if (hyphen == string::npos) { + // Nope, just one number. + int code; + if (!parse_code(word, code)) { + return false; + } + add_singleton(code); + + } else { + // Two numbers separated by a hyphen. + int from_code, to_code; + if (!parse_code(word.substr(0, hyphen), from_code)) { + return false; + } + if (!parse_code(word.substr(hyphen + 1), to_code)) { + return false; + } + add_range(from_code, to_code); + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::parse_code +// Access: Private +// Description: Parses a single numeric value, either decimal or +// hexadecimal, and stores it in the indicated +// parameter. Returns true if successful, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool RangeDescription:: +parse_code(const string &word, int &code) { + string str = trim(word); + const char *nptr = str.c_str(); + char *endptr; + code = strtol(nptr, &endptr, 0); + if (*endptr == '\0') { + return true; + } + + nout << "Invalid Unicode value: " << word << "\n"; + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeDescription::parse_bracket +// Access: Private +// Description: Parses the text listed between square brackets on the +// command line. +//////////////////////////////////////////////////////////////////// +bool RangeDescription:: +parse_bracket(const string &str) { + int last = 0; + bool continue_hyphen = false; + + string::const_iterator si; + si = str.begin(); + while (si != str.end()) { + int ch = (*si); + ++si; + if (si != str.end() && (*si) == '-') { + // A hyphen indicates a range. + ++si; + if (si == str.end()) { + // Unless the hyphen is the last character. + add_singleton(ch); + add_singleton('-'); + } else { + add_range(ch, (*si)); + ++si; + } + } else { + // Anything other than a hyphen indicates a singleton. + add_singleton(ch); + } + } + + return true; +} diff --git a/pandatool/src/egg-mkfont/rangeDescription.h b/pandatool/src/egg-mkfont/rangeDescription.h new file mode 100644 index 0000000000..4d6fd83bf0 --- /dev/null +++ b/pandatool/src/egg-mkfont/rangeDescription.h @@ -0,0 +1,68 @@ +// Filename: rangeDescription.h +// Created by: drose (07Sep03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef RANGEDESCRIPTION_H +#define RANGEDESCRIPTION_H + +#include "pandatoolbase.h" +#include "pvector.h" + +//////////////////////////////////////////////////////////////////// +// Class : RangeDescription +// Description : This describes a sparse range of Unicode character +// codes for conversion that may be specified on the +// command line. +//////////////////////////////////////////////////////////////////// +class RangeDescription { +public: + RangeDescription(); + + bool parse_parameter(const string ¶m); + INLINE void add_singleton(int code); + INLINE void add_range(int from_code, int to_code); + INLINE bool is_empty() const; + + void output(ostream &out) const; + +private: + bool parse_word(const string &word); + bool parse_code(const string &word, int &code); + bool parse_bracket(const string &str); + +private: + class Range { + public: + INLINE Range(int code); + INLINE Range(int from_code, int to_code); + + int _from_code; + int _to_code; + }; + + typedef pvector RangeList; + RangeList _range_list; + + friend class RangeIterator; +}; + +INLINE ostream &operator << (ostream &out, const RangeDescription &range); + +#include "rangeDescription.I" + +#endif + diff --git a/pandatool/src/egg-mkfont/charBitmap.I b/pandatool/src/egg-mkfont/rangeIterator.I similarity index 63% rename from pandatool/src/egg-mkfont/charBitmap.I rename to pandatool/src/egg-mkfont/rangeIterator.I index 367e162475..df5ee57e71 100644 --- a/pandatool/src/egg-mkfont/charBitmap.I +++ b/pandatool/src/egg-mkfont/rangeIterator.I @@ -1,5 +1,5 @@ -// Filename: charBitmap.I -// Created by: drose (16Feb01) +// Filename: rangeIterator.I +// Created by: drose (07Sep03) // //////////////////////////////////////////////////////////////////// // @@ -18,21 +18,23 @@ //////////////////////////////////////////////////////////////////// -// Function: CharBitmap::get_width +// Function: RangeIterator::get_code // Access: Public -// Description: Returns the width of the character in pixels. +// Description: Returns the current Unicode value represented by the +// iterator, or -1 if the iterator has reached the end. //////////////////////////////////////////////////////////////////// -INLINE int CharBitmap:: -get_width() const { - return _block.empty() ? 0 : _block[0].size(); +INLINE int RangeIterator:: +get_code() const { + return _code; } //////////////////////////////////////////////////////////////////// -// Function: CharBitmap::get_height +// Function: RangeIterator::eof // Access: Public -// Description: Returns the height of the character in pixels. +// Description: Returns true if all the code have been retrieved, +// false otherwise. //////////////////////////////////////////////////////////////////// -INLINE int CharBitmap:: -get_height() const { - return _block.size(); +INLINE bool RangeIterator:: +eof() const { + return (_it == _desc._range_list.end()); } diff --git a/pandatool/src/egg-mkfont/rangeIterator.cxx b/pandatool/src/egg-mkfont/rangeIterator.cxx new file mode 100644 index 0000000000..1ead5113d6 --- /dev/null +++ b/pandatool/src/egg-mkfont/rangeIterator.cxx @@ -0,0 +1,74 @@ +// Filename: rangeIterator.cxx +// Created by: drose (07Sep03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "rangeIterator.h" + +//////////////////////////////////////////////////////////////////// +// Function: RangeIterator::Constructor +// Access: Public +// Description: Constructs an iterator to walk through the codes on +// the descriptor. It is important not to modify the +// RangeDescription object during the lifetime of the +// iterator. +//////////////////////////////////////////////////////////////////// +RangeIterator:: +RangeIterator(const RangeDescription &desc) : + _desc(desc) +{ + _it = _desc._range_list.begin(); + if (_it == _desc._range_list.end()) { + _code = -1; + } else { + _code = (*_it)._from_code; + _codes_generated.insert(_code); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RangeIterator::next +// Access: Public +// Description: Advances the iterator to the next code. Returns true +// if there is a next code, or false if there are no +// mode codes. +//////////////////////////////////////////////////////////////////// +bool RangeIterator:: +next() { + do { + if (_it == _desc._range_list.end()) { + return false; + } + + if (_code < (*_it)._to_code) { + _code++; + + } else { + _it++; + if (_it == _desc._range_list.end()) { + _code = -1; + return false; + } + + _code = (*_it)._from_code; + } + + // If this code has already been generated, repeat and skip to the + // next one. + } while (!_codes_generated.insert(_code).second); + + return true; +} diff --git a/pandatool/src/egg-mkfont/charPlacement.I b/pandatool/src/egg-mkfont/rangeIterator.h similarity index 51% rename from pandatool/src/egg-mkfont/charPlacement.I rename to pandatool/src/egg-mkfont/rangeIterator.h index 104fda2c3b..e0fb2e9414 100644 --- a/pandatool/src/egg-mkfont/charPlacement.I +++ b/pandatool/src/egg-mkfont/rangeIterator.h @@ -1,5 +1,5 @@ -// Filename: charPlacement.I -// Created by: drose (16Feb01) +// Filename: rangeIterator.h +// Created by: drose (07Sep03) // //////////////////////////////////////////////////////////////////// // @@ -16,19 +16,37 @@ // //////////////////////////////////////////////////////////////////// +#ifndef RANGEITERATOR_H +#define RANGEITERATOR_H + +#include "pandatoolbase.h" +#include "rangeDescription.h" + +#include "pset.h" //////////////////////////////////////////////////////////////////// -// Function: CharPlacement::Constructor -// Access: Public -// Description: +// Class : RangeIterator +// Description : Walks through all the Unicode characters described by +// a RangeDescription class. //////////////////////////////////////////////////////////////////// -INLINE CharPlacement:: -CharPlacement(const CharBitmap *bm, int x, int y, - int width, int height) : - _bm(bm), - _x(x), - _y(y), - _width(width), - _height(height) -{ -} +class RangeIterator { +public: + RangeIterator(const RangeDescription &desc); + + INLINE int get_code() const; + bool next(); + INLINE bool eof() const; + +private: + const RangeDescription &_desc; + RangeDescription::RangeList::const_iterator _it; + int _code; + + typedef pset Codes; + Codes _codes_generated; +}; + +#include "rangeIterator.I" + +#endif + diff --git a/pandatool/src/egg-mkfont/ttf2egg b/pandatool/src/egg-mkfont/ttf2egg deleted file mode 100755 index 77830523c7..0000000000 --- a/pandatool/src/egg-mkfont/ttf2egg +++ /dev/null @@ -1,134 +0,0 @@ -#!/bin/sh -# -# Converts from a TTF font file to an egg file and associated texture map -# that is suitable for using with the TextNode class in Panda to render -# text in the world. -# -# This script takes advantage of ttf2tfm and ttf2pk, two programs that -# can be found in the freetype project--see www.freetype.org. Look -# in the contrib subdirectory of freetype-1.3.1; it doesn't seem to exist -# yet in freetype-2.0. -# -# -# Usage: -# -# ttf2egg [opts] file.ttf file.egg -- [mkfont-opts] -# -# Options that control the behavior of this script must appear first. -# The extra options options following the first two parameters are passed -# unchanged to egg-mkfont. -# -# Local options: -# -# -d dpi -# Specify the resolution at which to rasterize the font before -# converting it. This affects the size of the generated texture -# image and, in turn, the clarity of the resulting font. The -# default is 720, which generally seems to be a good ratio. -# -# -T file.enc -# Specify the name and/or location of the encoding file to use -# to convert the glyphs from the TTF font. A couple of suitable -# files are provided with ttf2tfm; most of the time, you will -# want to use T1-WGL4.enc. -# -# See egg-mkfont -h for a description of the additional options. -# -#ENDCOMMENT - -showhelp= -dpi=720 -enc=$PANDATOOL/shared/T1-WGL4.enc -while getopts "d:T:h" flag; do - case $flag in - d) dpi="$OPTARG";; - T) enc="$OPTARG";; - h) showhelp=y;; - \?) exit 1; - esac -done - -if [ -z "$1" -o -z "$2" -o "$showhelp" ]; then - sed '/#ENDCOMMENT/,$d' <$0 >&2 - exit 1 -fi - -shift `expr $OPTIND - 1` - -ttf="$1" -egg=$2 - -# Perform some sanity checks on input parameters. - -if [ -f "$ttf" ]; then - basettf=`basename "$ttf" .ttf` - baseTTF=`basename "$ttf" .TTF` - base=`basename "$ttf"` - if [ "$basettf" = "$base" -a "$baseTTF" = "$base" ]; then - echo "$ttf should end in .ttf or .TTF" - exit 1 - fi -else - echo "$ttf does not exist." - exit 1 -fi - -if [ `basename $egg .egg` = `basename $egg` ]; then - echo "$egg should end in .egg" - exit 1 -fi - -fontname=`basename $egg .egg` -shift 2 - -if [ "x$1" = "x--" ]; then - shift -fi - -# Create a temporary TTF filename in case the source filename has bad -# characters (like spaces). -tempttf=$fontname.ttf -if [ $tempttf != "$ttf" ]; then - echo ln -s \"$ttf\" $tempttf - if ln -s "$ttf" $tempttf; then - status=0 - else - echo Cannot create $tempttf - exit 1 - fi -fi - -status=0 -rm -f ttfonts1.map -echo ttf2tfm $tempttf -q -u -T \"$enc\" \"$fontname.tfm\" -if ttf2tfm $tempttf -q -u -T "$enc" "$fontname.tfm" > ttfonts1.map 2>/dev/null; then - rm -f ttfonts.map - tail -1 ttfonts1.map >ttfonts.map - echo ttf2pk -q \"$fontname\" $dpi - if ttf2pk -q "$fontname" $dpi >/dev/null 2>/dev/null; then - echo egg-mkfont $* -o \"$egg\" \"$fontname.${dpi}pk\" - egg-mkfont $* -o "$egg" "$fontname.${dpi}pk" - status=$? - else - echo Error running ttf2pk. - status=1 - fi -else - echo Error running ttf2tfm. - status=1 -fi - -rm -f ttfonts1.map ttfonts.map "$fontname.tfm" "$fontname.${dpi}pk" -if [ $tempttf != "$ttf" ]; then - rm -f $tempttf -fi - -if [ $status != 0 ]; then - echo "" - echo "***************************" - echo "*** Cannot convert $ttf ***" - echo "***************************" - echo "" -fi - -exit $status diff --git a/pandatool/src/progbase/programBase.cxx b/pandatool/src/progbase/programBase.cxx index 1ac66a3793..a1fa6335ac 100644 --- a/pandatool/src/progbase/programBase.cxx +++ b/pandatool/src/progbase/programBase.cxx @@ -944,9 +944,8 @@ dispatch_double_quad(const string &opt, const string &arg, void *var) { // Function: ProgramBase::dispatch_color // Access: Protected, Static // Description: Standard dispatch function for an option that takes a -// color, either as r,g,b or as r,g,b,a. The data -// pointer is to an array of four floats, e.g. a -// Colorf. +// color, as l or l,a or r,g,b or r,g,b,a. The data +// pointer is to an array of four floats, e.g. a Colorf. //////////////////////////////////////////////////////////////////// bool ProgramBase:: dispatch_color(const string &opt, const string &arg, void *var) { @@ -956,24 +955,43 @@ dispatch_color(const string &opt, const string &arg, void *var) { tokenize(arg, words, ","); bool okflag = false; - if (words.size() == 4) { + switch (words.size()) { + case 4: okflag = string_to_float(words[0], ip[0]) && string_to_float(words[1], ip[1]) && string_to_float(words[2], ip[2]) && string_to_float(words[3], ip[3]); + break; - } else if (words.size() == 3) { + case 3: okflag = string_to_float(words[0], ip[0]) && string_to_float(words[1], ip[1]) && string_to_float(words[2], ip[2]); ip[3] = 1.0; + break; + + case 2: + okflag = + string_to_float(words[0], ip[0]) && + string_to_float(words[1], ip[3]); + ip[1] = ip[0]; + ip[2] = ip[0]; + break; + + case 1: + okflag = + string_to_float(words[0], ip[0]); + ip[1] = ip[0]; + ip[2] = ip[0]; + ip[3] = 1.0; + break; } if (!okflag) { nout << "-" << opt - << " requires three or four numbers separated by commas.\n"; + << " requires one through four numbers separated by commas.\n"; return false; }