Browse Source

new egg-mkfont

David Rose 22 years ago
parent
commit
abb0c97f85

+ 13 - 13
pandatool/src/egg-mkfont/Sources.pp

@@ -1,3 +1,7 @@
+#define BUILD_DIRECTORY $[HAVE_FREETYPE]
+
+#define USE_PACKAGES freetype
+
 #define LOCAL_LIBS \
 #define LOCAL_LIBS \
   eggbase progbase
   eggbase progbase
 #define OTHER_LIBS \
 #define OTHER_LIBS \
@@ -5,24 +9,20 @@
   egg:c linmath:c putil:c express:c pandaegg:m panda:m pandaexpress:m \
   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
   dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
 
 
-#define UNIX_SYS_LIBS m
-
 #begin bin_target
 #begin bin_target
   #define TARGET egg-mkfont
   #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 \
   #define INCLUDED_SOURCES \
-    charBitmap.cxx charLayout.cxx \
-    charPlacement.cxx eggMakeFont.cxx \
-    fontFile.cxx pkFontFile.cxx \
+    eggMakeFont.cxx \
+    rangeDescription.cxx \
+    rangeIterator.cxx
 
 
 #end bin_target
 #end bin_target
-
-#define INSTALL_SCRIPTS ttf2egg pfb2egg
-#define INSTALL_DATA T1-WGL4.enc

+ 0 - 128
pandatool/src/egg-mkfont/T1-WGL4.enc

@@ -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

+ 0 - 76
pandatool/src/egg-mkfont/charBitmap.cxx

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "charBitmap.h"
-
-#include <notify.h>
-
-
-////////////////////////////////////////////////////////////////////
-//     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());
-}

+ 0 - 56
pandatool/src/egg-mkfont/charBitmap.h

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-#ifndef CHARBITMAP_H
-#define CHARBITMAP_H
-
-#include <pandatoolbase.h>
-
-#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<char> Row;
-  typedef pvector<Row> 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

+ 0 - 127
pandatool/src/egg-mkfont/charLayout.cxx

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "charLayout.h"
-#include "charBitmap.h"
-
-#include <notify.h>
-
-////////////////////////////////////////////////////////////////////
-//     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;
-}

+ 0 - 55
pandatool/src/egg-mkfont/charLayout.h

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef CHARLAYOUT_H
-#define CHARLAYOUT_H
-
-#include <pandatoolbase.h>
-
-#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<CharPlacement> 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

+ 0 - 41
pandatool/src/egg-mkfont/charPlacement.cxx

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#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);
-}

+ 0 - 48
pandatool/src/egg-mkfont/charPlacement.h

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef CHARPLACEMENT_H
-#define CHARPLACEMENT_H
-
-#include <pandatoolbase.h>
-
-#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

+ 0 - 5
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 "eggMakeFont.cxx"
-#include "fontFile.cxx"
-#include "pkFontFile.cxx"

+ 274 - 693
pandatool/src/egg-mkfont/eggMakeFont.cxx

@@ -17,19 +17,16 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "eggMakeFont.h"
 #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 "eggGroup.h"
+#include "eggPoint.h"
+#include "eggPolygon.h"
 #include "eggTexture.h"
 #include "eggTexture.h"
 #include "eggVertexPool.h"
 #include "eggVertexPool.h"
-#include "eggPolygon.h"
-#include "eggPoint.h"
-#include "pointerTo.h"
-
-#include <math.h>
+#include "eggVertex.h"
+#include "string_utils.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMakeFont::Constructor
 //     Function: EggMakeFont::Constructor
@@ -39,36 +36,31 @@
 EggMakeFont::
 EggMakeFont::
 EggMakeFont() : EggWriter(true, false) {
 EggMakeFont() : EggWriter(true, false) {
   set_program_description
   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();
   clear_runlines();
-  add_runline("[opts] -o output.egg file.pk");
-  add_runline("[opts] file.pk 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_runline("[opts] -o output.egg font");
+  add_runline("[opts] font output.egg");
 
 
   add_option
   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
   add_option
     ("fg", "r,g,b[,a]", 0,
     ("fg", "r,g,b[,a]", 0,
@@ -80,115 +72,81 @@ EggMakeFont() : EggWriter(true, false) {
   add_option
   add_option
     ("bg", "r,g,b[,a]", 0,
     ("bg", "r,g,b[,a]", 0,
      "Specifies the background color of the generated texture map.  The "
      "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 "
      "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]);
      &EggMakeFont::dispatch_color, NULL, &_bg[0]);
 
 
   add_option
   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);
-
-  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);
-
-  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);
+    ("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
   add_option
-    ("g", "radius", 0,
-     "The radius of the Gaussian filter used to antialias the letters. [1.2]",
-     &EggMakeFont::dispatch_double, NULL, &_gaussian_radius);
+    ("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
   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);
+    ("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
   add_option
-    ("B", "n", 0,
+    ("bp", "n", 0,
      "The number of extra pixels around a single character in the "
      "The number of extra pixels around a single character in the "
      "generated polygon. [1.0]",
      "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);
+     &EggMakeFont::dispatch_double, NULL, &_poly_margin);
 
 
   add_option
   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);
+    ("bt", "n", 0,
+     "The number of extra pixels around each character in the texture map.",
+     &EggMakeFont::dispatch_double, NULL, &_tex_margin);
 
 
   add_option
   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);
+    ("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 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
   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);
   _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::
 bool EggMakeFont::
 handle_args(ProgramBase::Args &args) {
 handle_args(ProgramBase::Args &args) {
   if (args.empty()) {
   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;
     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.
-////////////////////////////////////////////////////////////////////
-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);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggMakeFont::ns_dispatch_dimensions
-//       Access: Protected
-//  Description: Reads the dimensions of the output image and stores
-//               them in _output_[xyz]size.
+//     Function: EggMakeFont::run
+//       Access: Public
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-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);
+void EggMakeFont::
+run() {
+  _text_maker = new PNMTextMaker(_input_font_filename, _face_index);
+  if (!_text_maker->is_valid()) {
+    exit(1);
   }
   }
-
-  if (!okflag) {
-    nout << "-" << opt
-         << " requires two or three integers separated by commas.\n";
-    return false;
+  _text_maker->set_point_size(_point_size);
+  _text_maker->set_scale_factor(_scale_factor);
+  _text_maker->set_pixels_per_unit(_pixels_per_unit);
+
+  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";
   }
   }
 
 
-  return true;
-}
+  // 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;
+    }
+  }      
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggMakeFont::get_uv
-//       Access: Private
-//  Description: Given the X, Y coordinates of a particular pixel on
-//               the image, return the corresponding UV coordinates.
-////////////////////////////////////////////////////////////////////
-TexCoordd EggMakeFont::
-get_uv(double x, double y) {
-  return TexCoordd(x / (double)_working_xsize,
-                   ((double)_working_ysize - y) / (double)_working_ysize);
-}
+  _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_xy
-//       Access: Private
-//  Description: Given X, Y coordinates in pixels, scale to unit
-//               coordinates for the character's geometry.
+//     Function: EggMakeFont::dispatch_range
+//       Access: Private, Static
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-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,551 +281,147 @@ make_vertex(const LPoint2d &xy) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: EggMakeFont::copy_character
+//     Function: EggMakeFont::add_character
 //       Access: Private
 //       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::
 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.
-
-  // 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]));
+  make_geom(glyph, code);
+}
 
 
-  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.
   // Create an egg group to hold the polygon.
   string group_name = format_string(character);
   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();
     EggPolygon *poly = new EggPolygon();
     group->add_child(poly);
     group->add_child(poly);
-    poly->set_texture(_tref);
+    poly->set_texture(get_tref(glyph, character));
 
 
     poly->add_vertex(v1);
     poly->add_vertex(v1);
     poly->add_vertex(v2);
     poly->add_vertex(v2);
     poly->add_vertex(v3);
     poly->add_vertex(v3);
     poly->add_vertex(v4);
     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;
-}
-
-////////////////////////////////////////////////////////////////////
-//     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;
-  }
+  // Now create a single point where the origin of the next character
+  // will be.
 
 
-  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);
-  }
+  EggVertex *v0 = make_vertex(LPoint2d(glyph->get_advance() / _pixels_per_unit, 0.0));
+  EggPoint *point = new EggPoint;
+  group->add_child(point);
+  point->add_vertex(v0);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: EggMakeFont::choose_scale_factor
+//     Function: EggMakeFont::get_tref
 //       Access: Private
 //       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;
+//  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;
   }
   }
 
 
-  choose_scale_factor(too_small, too_large);
-  return true;
+  EggTexture *tref = make_tref(glyph, character);
+  _trefs[glyph] = tref;
+  return tref;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: EggMakeFont::choose_image_size
+//     Function: EggMakeFont::make_tref
 //       Access: Private
 //       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);
+//  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);
 
 
-////////////////////////////////////////////////////////////////////
-//     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);
-      }
-    }
+  if (!image.write(texture_filename)) {
+    nout << "Unable to write " << texture_filename << "\n";
   }
   }
-}
 
 
-////////////////////////////////////////////////////////////////////
-//     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;
-    }
+  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);
 
 
-    last = zp + 1;
-    hyphen = str.find('-', last + 1);
-  }
-
-  result += str.substr(last);
-  return result;
+  return tref;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     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));
-  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();
-}
-
-
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
   EggMakeFont prog;
   EggMakeFont prog;
   prog.parse_command_line(argc, argv);
   prog.parse_command_line(argc, argv);

+ 36 - 59
pandatool/src/egg-mkfont/eggMakeFont.h

@@ -20,27 +20,25 @@
 #define EGGMAKEFONT_H
 #define EGGMAKEFONT_H
 
 
 #include "pandatoolbase.h"
 #include "pandatoolbase.h"
-
-#include "charLayout.h"
+#include "rangeDescription.h"
 
 
 #include "eggWriter.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 EggVertexPool;
-class EggVertex;
-class FontFile;
+class EggGroup;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : EggMakeFont
 //       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 {
 class EggMakeFont : public EggWriter {
 public:
 public:
@@ -48,62 +46,41 @@ public:
 
 
 protected:
 protected:
   virtual bool handle_args(Args &args);
   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);
+
+public:
+  void run();
 
 
 private:
 private:
-  TexCoordd get_uv(double x, double y);
-  LPoint2d get_xy(double x, double y);
+  static bool dispatch_range(const string &, const string &arg, void *var);
   EggVertex *make_vertex(const LPoint2d &xy);
   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();
+  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:
 private:
-  Filename _output_image_filename;
-  Filename _input_font_filename;
-  bool _got_output_size;
   Colorf _fg, _bg;
   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;
   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<int, PT(EggGroup)> 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;
   EggVertexPool *_vpool;
   EggGroup *_group;
   EggGroup *_group;
-  EggTexture *_tref;
+
+  typedef pmap<PNMTextGlyph *, EggTexture *> TRefs;
+  TRefs _trefs;
 };
 };
 
 
 
 

+ 0 - 91
pandatool/src/egg-mkfont/fontFile.I

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     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];
-}

+ 0 - 67
pandatool/src/egg-mkfont/fontFile.cxx

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "fontFile.h"
-#include "charBitmap.h"
-
-#include <algorithm>
-
-
-// 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());
-}

+ 0 - 65
pandatool/src/egg-mkfont/fontFile.h

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef FONTFILE_H
-#define FONTFILE_H
-
-#include <pandatoolbase.h>
-
-#include <filename.h>
-#include <notify.h>
-
-#include <math.h>
-
-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<CharBitmap *> Chars;
-  Chars _chars;
-};
-
-#include "fontFile.I"
-
-#endif

+ 0 - 164
pandatool/src/egg-mkfont/pfb2egg

@@ -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

+ 0 - 916
pandatool/src/egg-mkfont/pkFontFile.cxx

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#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.
-
-@<Packed number procedure@>=
-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!') ;
[email protected] 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;
-}

+ 0 - 64
pandatool/src/egg-mkfont/pkFontFile.h

@@ -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
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef PKFONTFILE_H
-#define PKFONTFILE_H
-
-#include <pandatoolbase.h>
-
-#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<unsigned char> _pk;
-};
-
-#endif

+ 78 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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;
+}

+ 199 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &param) {
+  // 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;
+}

+ 68 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &param);
+  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<Range> RangeList;
+  RangeList _range_list;
+
+  friend class RangeIterator;
+};
+
+INLINE ostream &operator << (ostream &out, const RangeDescription &range);
+
+#include "rangeDescription.I"
+
+#endif
+

+ 14 - 12
pandatool/src/egg-mkfont/charBitmap.I → 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
 //       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
 //       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());
 }
 }

+ 74 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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;
+}

+ 33 - 15
pandatool/src/egg-mkfont/charPlacement.I → 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<int> Codes;
+  Codes _codes_generated;
+};
+
+#include "rangeIterator.I"
+
+#endif
+

+ 0 - 134
pandatool/src/egg-mkfont/ttf2egg

@@ -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

+ 24 - 6
pandatool/src/progbase/programBase.cxx

@@ -944,9 +944,8 @@ dispatch_double_quad(const string &opt, const string &arg, void *var) {
 //     Function: ProgramBase::dispatch_color
 //     Function: ProgramBase::dispatch_color
 //       Access: Protected, Static
 //       Access: Protected, Static
 //  Description: Standard dispatch function for an option that takes a
 //  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::
 bool ProgramBase::
 dispatch_color(const string &opt, const string &arg, void *var) {
 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, ",");
   tokenize(arg, words, ",");
 
 
   bool okflag = false;
   bool okflag = false;
-  if (words.size() == 4) {
+  switch (words.size()) {
+  case 4:
     okflag =
     okflag =
       string_to_float(words[0], ip[0]) &&
       string_to_float(words[0], ip[0]) &&
       string_to_float(words[1], ip[1]) &&
       string_to_float(words[1], ip[1]) &&
       string_to_float(words[2], ip[2]) &&
       string_to_float(words[2], ip[2]) &&
       string_to_float(words[3], ip[3]);
       string_to_float(words[3], ip[3]);
+    break;
 
 
-  } else if (words.size() == 3) {
+  case 3:
     okflag =
     okflag =
       string_to_float(words[0], ip[0]) &&
       string_to_float(words[0], ip[0]) &&
       string_to_float(words[1], ip[1]) &&
       string_to_float(words[1], ip[1]) &&
       string_to_float(words[2], ip[2]);
       string_to_float(words[2], ip[2]);
     ip[3] = 1.0;
     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) {
   if (!okflag) {
     nout << "-" << opt
     nout << "-" << opt
-         << " requires three or four numbers separated by commas.\n";
+         << " requires one through four numbers separated by commas.\n";
     return false;
     return false;
   }
   }