فهرست منبع

add pnmtext library

David Rose 22 سال پیش
والد
کامیت
6409ff6b7f

+ 1 - 1
panda/metalibs/panda/Sources.pp

@@ -17,7 +17,7 @@
     gsgmisc light linmath mathutil net \
     parametrics pnm \
     pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
-    switchnode text tform tiff lerp loader putil \
+    switchnode pnmtext text tform tiff lerp loader putil \
     audio pgui pandabase 
 
 

+ 188 - 0
panda/src/pnmtext/freetypeFont.I

@@ -0,0 +1,188 @@
+// Filename: freetypeFont.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: FreetypeFont::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE FreetypeFont::
+~FreetypeFont() {
+  unload_font();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::set_point_size
+//       Access: Public
+//  Description: Sets the point size of the font.  This controls the
+//               apparent size of the font onscreen.  By convention, a
+//               10 point font is about 1 screen unit high.
+//
+//               This should only be called before any characters have
+//               been requested out of the font, or immediately after
+//               calling clear().
+////////////////////////////////////////////////////////////////////
+INLINE bool FreetypeFont::
+set_point_size(float point_size) {
+  _point_size = point_size;
+  return reset_scale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_point_size
+//       Access: Public
+//  Description: Returns the point size of the font.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_point_size() const {
+  return _point_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::set_pixels_per_unit
+//       Access: Public
+//  Description: Set the resolution of the texture map, and hence the
+//               clarity of the resulting font.  This sets the number
+//               of pixels in the texture map that are used for each
+//               onscreen unit.
+//
+//               Setting this number larger results in an easier to
+//               read font, but at the cost of more texture memory.
+//
+//               This should only be called before any characters have
+//               been requested out of the font, or immediately after
+//               calling clear().
+////////////////////////////////////////////////////////////////////
+INLINE bool FreetypeFont::
+set_pixels_per_unit(float pixels_per_unit) {
+  _tex_pixels_per_unit = pixels_per_unit;
+  return reset_scale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_pixels_per_unit
+//       Access: Public
+//  Description: Returns the resolution of the texture map.  See
+//               set_pixels_per_unit().
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_pixels_per_unit() const {
+  return _tex_pixels_per_unit;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::set_pixel_size
+//       Access: Public
+//  Description: Computes the appropriate pixels_per_unit value to set
+//               the size of the font in the texture to the indicated
+//               number of pixels.  This is just another way to
+//               specify pixels_per_unit().
+////////////////////////////////////////////////////////////////////
+INLINE bool FreetypeFont::
+set_pixel_size(float pixel_size) {
+  return set_pixels_per_unit(pixel_size * _points_per_unit / _point_size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_pixel_size
+//       Access: Public
+//  Description: Returns the size of the font in pixels, as it appears
+//               in the texture.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_pixel_size() const {
+  return _tex_pixels_per_unit * _point_size / _points_per_unit;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::set_scale_factor
+//       Access: Public
+//  Description: Sets the factor by which the font is rendered larger
+//               by the FreeType library before being filtered down to
+//               its actual size in the texture as specified by
+//               set_pixels_per_unit().  This may be set to a number
+//               larger than 1.0 to improve the font's antialiasing
+//               (since FreeType doesn't really do a swell job of
+//               antialiasing by itself).  There is some performance
+//               implication for setting this different than 1.0.
+//
+//               This should only be called before any characters have
+//               been requested out of the font, or immediately after
+//               calling clear().
+////////////////////////////////////////////////////////////////////
+INLINE bool FreetypeFont::
+set_scale_factor(float scale_factor) {
+  _scale_factor = scale_factor;
+  return reset_scale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_scale_factor
+//       Access: Public
+//  Description: Returns the antialiasing scale factor.  See
+//               set_scale_factor().
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_scale_factor() const {
+  return _scale_factor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_line_height
+//       Access: Public
+//  Description: Returns the number of units high each line of text
+//               is.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_line_height() const {
+  return _line_height;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_space_advance
+//       Access: Public
+//  Description: Returns the number of units wide a space is.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_space_advance() const {
+  return _space_advance;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_points_per_unit
+//       Access: Public, Static
+//  Description: Returns the point size of the font that is one Panda
+//               unit high.  This is an arbitrary Panda convention for
+//               text, and is set to 10.0.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_points_per_unit() {
+  return _points_per_unit;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::get_points_per_inch
+//       Access: Public, Static
+//  Description: Returns the number of points in one inch.  This is a
+//               universal typographic convention.
+////////////////////////////////////////////////////////////////////
+INLINE float FreetypeFont::
+get_points_per_inch() {
+  return _points_per_inch;
+}

+ 379 - 0
panda/src/pnmtext/freetypeFont.cxx

@@ -0,0 +1,379 @@
+// Filename: freetypeFont.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 "freetypeFont.h"
+
+#ifdef HAVE_FREETYPE
+
+#include "config_pnmtext.h"
+#include "config_util.h"
+#include "config_express.h"
+#include "virtualFileSystem.h"
+
+FT_Library FreetypeFont::_ft_library;
+bool FreetypeFont::_ft_initialized = false;
+bool FreetypeFont::_ft_ok = false;
+
+// This constant determines how big a particular point size font
+// appears to be.  By convention, 10 points is 1 unit (e.g. 1 foot)
+// high.
+const float FreetypeFont::_points_per_unit = 10.0f;
+
+// A universal typographic convention.
+const float FreetypeFont::_points_per_inch = 72.0f;
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FreetypeFont::
+FreetypeFont() {
+  _font_loaded = false;
+
+  _point_size = text_point_size;
+  _tex_pixels_per_unit = text_pixels_per_unit;
+  _scale_factor = text_scale_factor;
+
+  _line_height = 1.0f;
+  _space_advance = 0.25f;
+
+  if (!_ft_initialized) {
+    initialize_ft_library();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::load_font
+//       Access: Protected
+//  Description: This method accepts the name of some font file
+//               that FreeType can read, along with face_index,
+//               indicating which font within the file to load
+//               (usually 0).
+////////////////////////////////////////////////////////////////////
+bool FreetypeFont::
+load_font(const Filename &font_filename, int face_index) {
+  if (!_ft_ok) {
+    pnmtext_cat.error()
+      << "Unable to read font " << font_filename
+      << ": FreeType library not initialized properly.\n";
+    return false;
+  }
+
+  unload_font();
+
+  bool exists = false;
+  int error;
+  Filename path(font_filename);
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(path, get_model_path());
+    exists = vfs->read_file(path, _raw_font_data);
+    if (exists) {
+      error = FT_New_Memory_Face(_ft_library, 
+                                 (const FT_Byte *)_raw_font_data.data(),
+                                 _raw_font_data.length(),
+                                 face_index, &_face);
+    }
+  } else {
+    path.resolve_filename(get_model_path());
+    exists = path.exists();
+    if (exists) {
+      string os_specific = path.to_os_specific();
+      error = FT_New_Face(_ft_library, os_specific.c_str(),
+                          face_index, &_face);
+    }
+  }
+
+  if (!exists) {
+    pnmtext_cat.error()
+      << "Unable to find font file " << font_filename << "\n";
+  } else {
+    if (error == FT_Err_Unknown_File_Format) {
+      pnmtext_cat.error()
+        << "Unable to read font " << font_filename << ": unknown file format.\n";
+    } else if (error) {
+      pnmtext_cat.error()
+        << "Unable to read font " << font_filename << ": invalid.\n";
+
+    } else {
+      return font_loaded();
+    }
+  }
+  
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::load_font
+//       Access: Protected
+//  Description: This method accepts a table of data representing
+//               the font file, loaded from some source other than a
+//               filename on disk.
+////////////////////////////////////////////////////////////////////
+bool FreetypeFont::
+load_font(const char *font_data, int data_length, int face_index) {
+  if (!_ft_ok) {
+    pnmtext_cat.error()
+      << "Unable to read font: FreeType library not initialized properly.\n";
+    return false;
+  }
+
+  unload_font();
+
+  int error;
+  error = FT_New_Memory_Face(_ft_library, 
+                             (const FT_Byte *)font_data, data_length,
+                             face_index, &_face);
+
+  if (error == FT_Err_Unknown_File_Format) {
+    pnmtext_cat.error()
+      << "Unable to read font: unknown file format.\n";
+  } else if (error) {
+    pnmtext_cat.error()
+      << "Unable to read font: invalid.\n";
+    
+  } else {
+    return font_loaded();
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::unload_font
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void FreetypeFont::
+unload_font() {
+  if (_font_loaded) {
+    FT_Done_Face(_face);
+    _font_loaded = false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::copy_bitmap_to_pnmimage
+//       Access: Protected
+//  Description: Copies a bitmap as rendered by FreeType into a
+//               PNMImage, so it can be rescaled.
+////////////////////////////////////////////////////////////////////
+void FreetypeFont::
+copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image) {
+  if (bitmap.pixel_mode == ft_pixel_mode_grays && 
+      bitmap.num_grays == (int)image.get_maxval() + 1) {
+    // This is the easy case: we can copy the rendered glyph
+    // directly into our image, one pixel at a time.
+    unsigned char *buffer_row = bitmap.buffer;
+    for (int yi = 0; yi < bitmap.rows; yi++) {
+      for (int xi = 0; xi < bitmap.width; xi++) {
+        image.set_gray_val(xi, yi, buffer_row[xi]);
+      }
+      buffer_row += bitmap.pitch;
+    }
+    
+  } else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
+    // This is a little bit more work: we have to expand the
+    // one-bit-per-pixel bitmap into a one-byte-per-pixel image.
+    unsigned char *buffer_row = bitmap.buffer;
+    for (int yi = 0; yi < bitmap.rows; yi++) {
+      xelval maxval = image.get_maxval();
+      int bit = 0x80;
+      unsigned char *b = buffer_row;
+      for (int xi = 0; xi < bitmap.width; xi++) {
+        if (*b & bit) {
+          image.set_gray_val(xi, yi, maxval);
+        } else {
+          image.set_gray_val(xi, yi, 0);
+        }
+        bit >>= 1;
+        if (bit == 0) {
+          ++b;
+          bit = 0x80;
+        }
+      }
+      
+      buffer_row += bitmap.pitch;
+    }
+    
+    
+  } else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
+    // Here we must expand a grayscale pixmap with n levels of gray
+    // into our 256-level texture.
+    unsigned char *buffer_row = bitmap.buffer;
+    for (int yi = 0; yi < bitmap.rows; yi++) {
+      for (int xi = 0; xi < bitmap.width; xi++) {
+        image.set_gray(xi, yi, (float)buffer_row[xi] / (bitmap.num_grays - 1));
+      }
+      buffer_row += bitmap.pitch;
+    }
+    
+  } else {
+    pnmtext_cat.error()
+      << "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::font_loaded
+//       Access: Private
+//  Description: Called after a font has been successfully loaded,
+//               either from disk or from memory image.
+////////////////////////////////////////////////////////////////////
+bool FreetypeFont::
+font_loaded() {
+  string name = _face->family_name;
+  if (_face->style_name != NULL) {
+    name += " ";
+    name += _face->style_name;
+  }
+  set_name(name);
+  
+  pnmtext_cat.info()
+    << "Loaded font " << name << "\n";
+  _font_loaded = true;
+  reset_scale();
+
+  if (pnmtext_cat.is_debug()) {
+    pnmtext_cat.debug()
+      << name << " has " << _face->num_charmaps << " charmaps:\n";
+    for (int i = 0; i < _face->num_charmaps; i++) {
+      pnmtext_cat.debug(false) << " " << (void *)_face->charmaps[i];
+    }
+    pnmtext_cat.debug(false) << "\n";
+    pnmtext_cat.debug()
+      << "default charmap is " << (void *)_face->charmap << "\n";
+  }
+  if (_face->charmap == NULL) {
+    // If for some reason FreeType didn't set us up a charmap,
+    // then set it up ourselves.
+    if (_face->num_charmaps == 0) {
+      pnmtext_cat.warning()
+        << name << " has no charmaps available.\n";
+    } else {
+      pnmtext_cat.warning()
+        << name << " has no default Unicode charmap.\n";
+      if (_face->num_charmaps > 1) {
+        pnmtext_cat.warning()
+          << "Arbitrarily choosing first of " 
+          << _face->num_charmaps << " charmaps.\n";
+      }
+      FT_Set_Charmap(_face, _face->charmaps[0]);
+    }
+  }
+
+  return true;
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::reset_scale
+//       Access: Private
+//  Description: Resets the font based on the current values for
+//               _point_size, _tex_pixels_per_unit, and _scale_factor.
+//               Returns true if successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool FreetypeFont::
+reset_scale() {
+  // The font may be rendered larger (by a factor of _scale_factor),
+  // and then reduced into the texture.  Hence the difference between
+  // _font_pixels_per_unit and _tex_pixels_per_unit.
+  _font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
+
+  float units_per_inch = (_points_per_inch / _points_per_unit);
+  int dpi = (int)(_font_pixels_per_unit * units_per_inch);
+  
+  int error = FT_Set_Char_Size(_face,
+                               (int)(_point_size * 64), (int)(_point_size * 64),
+                               dpi, dpi);
+  if (error) {
+    // If we were unable to set a particular char size, perhaps we
+    // have a non-scalable font.  Try to figure out the closest
+    // available size.
+    int desired_height = (int)(_font_pixels_per_unit * _point_size / _points_per_unit + 0.5f);
+    int best_size = -1;
+    if (_face->num_fixed_sizes > 0) {
+      best_size = 0;
+      int best_diff = abs(desired_height - _face->available_sizes[0].height);
+      for (int i = 1; i < _face->num_fixed_sizes; i++) {
+        int diff = abs(desired_height - _face->available_sizes[i].height);
+        if (diff < best_diff) {
+          best_size = i;
+          best_diff = diff;
+        }
+      }
+    }
+    if (best_size >= 0) {
+      int pixel_height = _face->available_sizes[best_size].height;
+      int pixel_width = _face->available_sizes[best_size].width;
+      error = FT_Set_Pixel_Sizes(_face, pixel_width, pixel_height);
+      if (!error) {
+        pnmtext_cat.info()
+          << "Using " << pixel_height << "-pixel font for "
+          << get_name() << "\n";
+
+        _font_pixels_per_unit = pixel_height * _points_per_unit / _point_size;
+        _tex_pixels_per_unit = _font_pixels_per_unit;
+      }
+    }
+  }
+
+  if (error) {
+    pnmtext_cat.warning()
+      << "Unable to set " << get_name() 
+      << " to " << _point_size << "pt at " << dpi << " dpi.\n";
+    _line_height = 1.0f;
+    return false;
+  }
+
+  _line_height = _face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
+
+  // Determine the correct width for a space.
+  error = FT_Load_Char(_face, ' ', FT_LOAD_DEFAULT);
+  if (error) {
+    // Space isn't defined.  Oh well.
+    _space_advance = 0.25f * _line_height;
+
+  } else {
+    _space_advance = _face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::initialize_ft_library
+//       Access: Private, Static
+//  Description: Should be called exactly once to initialize the
+//               FreeType library.
+////////////////////////////////////////////////////////////////////
+void FreetypeFont::
+initialize_ft_library() {
+  if (!_ft_initialized) {
+    int error = FT_Init_FreeType(&_ft_library);
+    _ft_initialized = true;
+    if (error) {
+      pnmtext_cat.error()
+        << "Unable to initialize FreeType; dynamic fonts will not load.\n";
+    } else {
+      _ft_ok = true;
+    }
+  }
+}
+
+#endif  // HAVE_FREETYPE

+ 111 - 0
panda/src/pnmtext/freetypeFont.h

@@ -0,0 +1,111 @@
+// Filename: freetypeFont.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 FREETYPEFONT_H
+#define FREETYPEFONT_H
+
+#include "pandabase.h"
+
+#ifdef HAVE_FREETYPE
+
+#include "config_text.h"
+#include "filename.h"
+#include "pvector.h"
+#include "pmap.h"
+#include "namable.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+////////////////////////////////////////////////////////////////////
+//       Class : FreetypeFont
+// Description : This is a common base class for both DynamicTextFont
+//               and PNMTextMaker.  Both of these are utility classes
+//               that use the FreeType library to generate glyphs from
+//               fonts; this class abstracts out that common wrapper
+//               around FreeType.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA FreetypeFont : public Namable {
+protected:
+  FreetypeFont();
+
+  bool load_font(const Filename &font_filename, int face_index);
+  bool load_font(const char *font_data, int data_length, int face_index);
+  void unload_font();
+
+public:
+  INLINE ~FreetypeFont();
+
+  INLINE bool set_point_size(float point_size);
+  INLINE float get_point_size() const;
+
+  INLINE bool set_pixels_per_unit(float pixels_per_unit);
+  INLINE float get_pixels_per_unit() const;
+
+  INLINE bool set_pixel_size(float pixel_size);
+  INLINE float get_pixel_size() const;
+
+  INLINE bool set_scale_factor(float scale_factor);
+  INLINE float get_scale_factor() const;
+
+  INLINE float get_line_height() const;
+  INLINE float get_space_advance() const;
+
+  INLINE static float get_points_per_unit();
+  INLINE static float get_points_per_inch();
+
+protected:
+  void copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image);
+
+private:
+  bool font_loaded();
+  bool reset_scale();
+  static void initialize_ft_library();
+
+protected:
+  float _point_size;
+  float _tex_pixels_per_unit;
+  float _scale_factor;
+  float _font_pixels_per_unit;
+
+  float _line_height;
+  float _space_advance;
+
+  FT_Face _face;
+
+private:
+  bool _font_loaded;
+
+  // This string is used to hold the data read from the font file in
+  // vfs mode.  Since the FreeType library keeps pointers into this
+  // data, we have to keep it around.
+  string _raw_font_data;
+
+  static FT_Library _ft_library;
+  static bool _ft_initialized;
+  static bool _ft_ok;
+
+  static const float _points_per_unit;
+  static const float _points_per_inch;
+};
+
+#include "freetypeFont.I"
+
+#endif  // HAVE_FREETYPE
+
+#endif

+ 21 - 0
panda/src/putil/string_utils.cxx

@@ -189,6 +189,27 @@ trim_right(const string &str) {
   return str.substr(begin, end - begin);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: trim
+//  Description: Returns a new string representing the contents of the
+//               given string with both leading and trailing
+//               whitespace removed.
+////////////////////////////////////////////////////////////////////
+string
+trim(const string &str) {
+  size_t begin = 0;
+  while (begin < str.size() && isspace((unsigned int)str[begin])) {
+    begin++;
+  }
+
+  size_t end = str.size();
+  while (end > begin && isspace((unsigned int)str[end - 1])) {
+    end--;
+  }
+
+  return str.substr(begin, end - begin);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: string_to_int
 //  Description: A string-interface wrapper around the C library

+ 1 - 0
panda/src/putil/string_utils.h

@@ -47,6 +47,7 @@ EXPCL_PANDA void tokenize(const string &str, vector_string &words,
 // Trims leading and/or trailing whitespace from the string.
 EXPCL_PANDA string trim_left(const string &str);
 EXPCL_PANDA string trim_right(const string &str);
+EXPCL_PANDA string trim(const string &str);
 
 // Functions to parse numeric values out of a string.
 EXPCL_PANDA int string_to_int(const string &str, string &tail);

+ 1 - 1
panda/src/text/Sources.pp

@@ -7,7 +7,7 @@
   #define TARGET text
   #define LOCAL_LIBS \
     putil gobj pgraph linmath \
-    pnmimage gsgbase mathutil
+    pnmtext pnmimage gsgbase mathutil
     
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx 
 

+ 0 - 3
panda/src/text/config_text.cxx

@@ -42,9 +42,6 @@ const int text_texture_margin = config_text.GetInt("text-texture-margin", 2);
 const float text_poly_margin = config_text.GetFloat("text-poly-margin", 0.0f);
 const int text_page_x_size = config_text.GetInt("text-page-x-size", 256);
 const int text_page_y_size = config_text.GetInt("text-page-y-size", 256);
-const float text_point_size = config_text.GetFloat("text-point-size", 10.0f);
-const float text_pixels_per_unit = config_text.GetFloat("text-pixels-per-unit", 30.0f);
-const float text_scale_factor = config_text.GetFloat("text-scale-factor", 2.0f);
 const bool text_small_caps = config_text.GetBool("text-small-caps", false);
 const float text_small_caps_scale = config_text.GetFloat("text-small-caps-scale", 0.8f);
 const string text_default_font = config_text.GetString("text-default-font", "");

+ 0 - 3
panda/src/text/config_text.h

@@ -34,9 +34,6 @@ extern const int text_texture_margin;
 extern const float text_poly_margin;
 extern const int text_page_x_size;
 extern const int text_page_y_size;
-extern const float text_point_size;
-extern const float text_pixels_per_unit;
-extern const float text_scale_factor;
 extern const bool text_small_caps;
 extern const float text_small_caps_scale;
 extern const string text_default_font;

+ 44 - 9
panda/src/text/dynamicTextFont.I

@@ -17,6 +17,18 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::get_name
+//       Access: Public
+//  Description: Disambiguates the get_name() method between that
+//               inherited from TextFont and that inherited from
+//               FreetypeFont.
+////////////////////////////////////////////////////////////////////
+INLINE const string &DynamicTextFont::
+get_name() const {
+  return TextFont::get_name();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::set_point_size
 //       Access: Published
@@ -33,8 +45,7 @@ set_point_size(float point_size) {
   // If this assertion fails, you didn't call clear() first.  RTFM.
   nassertr(get_num_pages() == 0, false);
 
-  _point_size = point_size;
-  return reset_scale();
+  return FreetypeFont::set_point_size(point_size);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +55,7 @@ set_point_size(float point_size) {
 ////////////////////////////////////////////////////////////////////
 INLINE float DynamicTextFont::
 get_point_size() const {
-  return _point_size;
+  return FreetypeFont::get_point_size();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -67,8 +78,7 @@ set_pixels_per_unit(float pixels_per_unit) {
   // If this assertion fails, you didn't call clear() first.  RTFM.
   nassertr(get_num_pages() == 0, false);
 
-  _tex_pixels_per_unit = pixels_per_unit;
-  return reset_scale();
+  return FreetypeFont::set_pixels_per_unit(pixels_per_unit);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -79,7 +89,7 @@ set_pixels_per_unit(float pixels_per_unit) {
 ////////////////////////////////////////////////////////////////////
 INLINE float DynamicTextFont::
 get_pixels_per_unit() const {
-  return _tex_pixels_per_unit;
+  return FreetypeFont::get_pixels_per_unit();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -103,8 +113,7 @@ set_scale_factor(float scale_factor) {
   // If this assertion fails, you didn't call clear() first.  RTFM.
   nassertr(get_num_pages() == 0, false);
 
-  _scale_factor = scale_factor;
-  return reset_scale();
+  return FreetypeFont::set_scale_factor(scale_factor);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -115,7 +124,28 @@ set_scale_factor(float scale_factor) {
 ////////////////////////////////////////////////////////////////////
 INLINE float DynamicTextFont::
 get_scale_factor() const {
-  return _scale_factor;
+  return FreetypeFont::get_scale_factor();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::get_line_height
+//       Access: Public
+//  Description: Returns the number of units high each line of text
+//               is.
+////////////////////////////////////////////////////////////////////
+INLINE float DynamicTextFont::
+get_line_height() const {
+  return TextFont::get_line_height();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::get_space_advance
+//       Access: Public
+//  Description: Returns the number of units wide a space is.
+////////////////////////////////////////////////////////////////////
+INLINE float DynamicTextFont::
+get_space_advance() const {
+  return TextFont::get_space_advance();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -314,3 +344,8 @@ INLINE bool DynamicTextFont::
 get_update_cleared_glyphs() {
   return _update_cleared_glyphs;
 }
+
+INLINE ostream &
+operator << (ostream &out, const DynamicTextFont &dtf) {
+  return out << dtf.get_name();
+}

+ 11 - 301
panda/src/text/dynamicTextFont.cxx

@@ -27,21 +27,9 @@
 
 bool DynamicTextFont::_update_cleared_glyphs = text_update_cleared_glyphs;
 
-FT_Library DynamicTextFont::_ft_library;
-bool DynamicTextFont::_ft_initialized = false;
-bool DynamicTextFont::_ft_ok = false;
-
 TypeHandle DynamicTextFont::_type_handle;
 
 
-// This constant determines how big a particular point size font
-// appears to be.  By convention, 10 points is 1 unit (e.g. 1 foot)
-// high.
-static const float points_per_unit = 10.0f;
-
-// A universal typographic convention.
-static const float points_per_inch = 72.0f;
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::Constructor
 //       Access: Published
@@ -53,90 +41,10 @@ static const float points_per_inch = 72.0f;
 DynamicTextFont::
 DynamicTextFont(const Filename &font_filename, int face_index) {
   initialize();
-
-  if (!_ft_ok) {
-    text_cat.error()
-      << "Unable to read font " << font_filename
-      << ": FreeType library not initialized properly.\n";
-    return;
-  }
-
-  bool exists = false;
-  int error;
-  Filename path(font_filename);
-  if (use_vfs) {
-    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
-    vfs->resolve_filename(path, get_model_path());
-    exists = vfs->read_file(path, _raw_font_data);
-    if (exists) {
-      error = FT_New_Memory_Face(_ft_library, 
-                                 (const FT_Byte *)_raw_font_data.data(),
-                                 _raw_font_data.length(),
-                                 face_index, &_face);
-    }
-  } else {
-    path.resolve_filename(get_model_path());
-    exists = path.exists();
-    if (exists) {
-      string os_specific = path.to_os_specific();
-      error = FT_New_Face(_ft_library, os_specific.c_str(),
-                          face_index, &_face);
-    }
-  }
-
-  if (!exists) {
-    text_cat.error()
-      << "Unable to find font file " << font_filename << "\n";
-  } else {
-    if (error == FT_Err_Unknown_File_Format) {
-      text_cat.error()
-        << "Unable to read font " << font_filename << ": unknown file format.\n";
-    } else if (error) {
-      text_cat.error()
-        << "Unable to read font " << font_filename << ": invalid.\n";
-
-    } else {
-      string name = _face->family_name;
-      if (_face->style_name != NULL) {
-        name += " ";
-        name += _face->style_name;
-      }
-      set_name(name);
-
-      text_cat.info()
-        << "Loaded font " << get_name() << "\n";
-      _is_valid = true;
-      reset_scale();
-
-      if (text_cat.is_debug()) {
-        text_cat.debug()
-          << *this << " has " << _face->num_charmaps << " charmaps:\n";
-        for (int i = 0; i < _face->num_charmaps; i++) {
-          text_cat.debug(false) << " " << (void *)_face->charmaps[i];
-        }
-        text_cat.debug(false) << "\n";
-        text_cat.debug()
-          << "default charmap is " << (void *)_face->charmap << "\n";
-      }
-      if (_face->charmap == NULL) {
-        // If for some reason FreeType didn't set us up a charmap,
-        // then set it up ourselves.
-        if (_face->num_charmaps == 0) {
-          text_cat.warning()
-            << *this << " has no charmaps available.\n";
-        } else {
-          text_cat.warning()
-            << *this << " has no default Unicode charmap.\n";
-          if (_face->num_charmaps > 1) {
-            text_cat.warning()
-              << "Arbitrarily choosing first of " 
-              << _face->num_charmaps << " charmaps.\n";
-          }
-          FT_Set_Charmap(_face, _face->charmaps[0]);
-        }
-      }
-    }
-  }
+  _is_valid = load_font(font_filename, face_index);
+  TextFont::set_name(FreetypeFont::get_name());
+  TextFont::_line_height = FreetypeFont::get_line_height();
+  TextFont::_space_advance = FreetypeFont::get_space_advance();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -149,51 +57,19 @@ DynamicTextFont(const Filename &font_filename, int face_index) {
 DynamicTextFont::
 DynamicTextFont(const char *font_data, int data_length, int face_index) {
   initialize();
-
-  if (!_ft_ok) {
-    text_cat.error()
-      << "Unable to read font: FreeType library not initialized properly.\n";
-    return;
-  }
-
-  int error;
-  error = FT_New_Memory_Face(_ft_library, 
-                             (const FT_Byte *)font_data, data_length,
-                             face_index, &_face);
-
-  if (error == FT_Err_Unknown_File_Format) {
-    text_cat.error()
-      << "Unable to read font: unknown file format.\n";
-  } else if (error) {
-    text_cat.error()
-      << "Unable to read font: invalid.\n";
-    
-  } else {
-    string name = _face->family_name;
-    if (_face->style_name != NULL) {
-      name += " ";
-      name += _face->style_name;
-    }
-    set_name(name);
-    
-    text_cat.info()
-      << "Loaded font " << get_name() << "\n";
-    _is_valid = true;
-    reset_scale();
-  }
+  _is_valid = load_font(font_data, data_length, face_index);
+  TextFont::set_name(FreetypeFont::get_name());
+  TextFont::_line_height = FreetypeFont::_line_height;
+  TextFont::_space_advance = FreetypeFont::_space_advance;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::Constructor
+//     Function: DynamicTextFont::Destructor
 //       Access: Published, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 DynamicTextFont::
 ~DynamicTextFont() {
-  if (_is_valid) {
-    FT_Done_Face(_face);
-    _is_valid = false;
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -380,8 +256,8 @@ get_glyph(int character, const TextGlyph *&glyph) {
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::initialize
 //       Access: Private
-//  Description: Called from both constructors to set up some internal
-//               structures.
+//  Description: Called from both constructors to set up some initial
+//               values.
 ////////////////////////////////////////////////////////////////////
 void DynamicTextFont::
 initialize() {
@@ -389,9 +265,6 @@ initialize() {
   _poly_margin = text_poly_margin;
   _page_x_size = text_page_x_size;
   _page_y_size = text_page_y_size;
-  _point_size = text_point_size;
-  _tex_pixels_per_unit = text_pixels_per_unit;
-  _scale_factor = text_scale_factor;
 
   // We don't necessarily want to use mipmaps, since we don't want to
   // regenerate those every time the texture changes, but we probably
@@ -404,12 +277,7 @@ initialize() {
   // require generating mipmaps, but does require hardware support.
   _anisotropic_degree = text_anisotropic_degree;
 
-
   _preferred_page = 0;
-
-  if (!_ft_initialized) {
-    initialize_ft_library();
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -429,81 +297,6 @@ update_filters() {
     page->set_anisotropic_degree(_anisotropic_degree);
   }
 }
- 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::reset_scale
-//       Access: Private
-//  Description: Resets the font based on the current values for
-//               _point_size, _tex_pixels_per_unit, and _scale_factor.
-//               Returns true if successful, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool DynamicTextFont::
-reset_scale() {
-  // The font may be rendered larger (by a factor of _scale_factor),
-  // and then reduced into the texture.  Hence the difference between
-  // _font_pixels_per_unit aned _tex_pixels_per_unit.
-  _font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
-
-  float units_per_inch = (points_per_inch / points_per_unit);
-  int dpi = (int)(_font_pixels_per_unit * units_per_inch);
-  
-  int error = FT_Set_Char_Size(_face,
-                               (int)(_point_size * 64), (int)(_point_size * 64),
-                               dpi, dpi);
-  if (error) {
-    // If we were unable to set a particular char size, perhaps we
-    // have a non-scalable font.  Try to figure out the closest
-    // available size.
-    int desired_height = (int)(_font_pixels_per_unit * _point_size / points_per_unit + 0.5f);
-    int best_size = -1;
-    if (_face->num_fixed_sizes > 0) {
-      best_size = 0;
-      int best_diff = abs(desired_height - _face->available_sizes[0].height);
-      for (int i = 1; i < _face->num_fixed_sizes; i++) {
-        int diff = abs(desired_height - _face->available_sizes[i].height);
-        if (diff < best_diff) {
-          best_size = i;
-          best_diff = diff;
-        }
-      }
-    }
-    if (best_size >= 0) {
-      int pixel_height = _face->available_sizes[best_size].height;
-      int pixel_width = _face->available_sizes[best_size].width;
-      error = FT_Set_Pixel_Sizes(_face, pixel_width, pixel_height);
-      if (!error) {
-        text_cat.info()
-          << "Using " << pixel_height << "-pixel font for "
-          << get_name() << "\n";
-
-        _font_pixels_per_unit = pixel_height * points_per_unit / _point_size;
-        _tex_pixels_per_unit = _font_pixels_per_unit;
-      }
-    }
-  }
-
-  if (error) {
-    text_cat.warning()
-      << "Unable to set " << get_name() 
-      << " to " << _point_size << "pt at " << dpi << " dpi.\n";
-    _line_height = 1.0f;
-    return false;
-  }
-
-  _line_height = _face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
-
-  // Determine the correct width for a space.
-  error = FT_Load_Char(_face, ' ', FT_LOAD_DEFAULT);
-  if (error) {
-    // Space isn't defined.  Oh well.
-    _space_advance = 0.25f * _line_height;
-
-  } else {
-    _space_advance = _face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
-  }
-
-  return true;
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::make_glyph
@@ -643,68 +436,6 @@ copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::copy_bitmap_to_pnmimage
-//       Access: Private
-//  Description: Copies a bitmap as rendered by FreeType into a
-//               PNMImage, so it can be rescaled.
-////////////////////////////////////////////////////////////////////
-void DynamicTextFont::
-copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image) {
-  if (bitmap.pixel_mode == ft_pixel_mode_grays && 
-      bitmap.num_grays == (int)image.get_maxval() + 1) {
-    // This is the easy case: we can copy the rendered glyph
-    // directly into our image, one pixel at a time.
-    unsigned char *buffer_row = bitmap.buffer;
-    for (int yi = 0; yi < bitmap.rows; yi++) {
-      for (int xi = 0; xi < bitmap.width; xi++) {
-        image.set_gray_val(xi, yi, buffer_row[xi]);
-      }
-      buffer_row += bitmap.pitch;
-    }
-    
-  } else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
-    // This is a little bit more work: we have to expand the
-    // one-bit-per-pixel bitmap into a one-byte-per-pixel image.
-    unsigned char *buffer_row = bitmap.buffer;
-    for (int yi = 0; yi < bitmap.rows; yi++) {
-      xelval maxval = image.get_maxval();
-      int bit = 0x80;
-      unsigned char *b = buffer_row;
-      for (int xi = 0; xi < bitmap.width; xi++) {
-        if (*b & bit) {
-          image.set_gray_val(xi, yi, maxval);
-        } else {
-          image.set_gray_val(xi, yi, 0);
-        }
-        bit >>= 1;
-        if (bit == 0) {
-          ++b;
-          bit = 0x80;
-        }
-      }
-      
-      buffer_row += bitmap.pitch;
-    }
-    
-    
-  } else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
-    // Here we must expand a grayscale pixmap with n levels of gray
-    // into our 256-level texture.
-    unsigned char *buffer_row = bitmap.buffer;
-    for (int yi = 0; yi < bitmap.rows; yi++) {
-      for (int xi = 0; xi < bitmap.width; xi++) {
-        image.set_gray(xi, yi, (float)buffer_row[xi] / (bitmap.num_grays - 1));
-      }
-      buffer_row += bitmap.pitch;
-    }
-    
-  } else {
-    text_cat.error()
-      << "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::copy_pnmimage_to_texture
 //       Access: Private
@@ -783,25 +514,4 @@ slot_glyph(int x_size, int y_size) {
   }
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: DynamicTextFont::initialize_ft_library
-//       Access: Private, Static
-//  Description: Should be called exactly once to initialize the
-//               FreeType library.
-////////////////////////////////////////////////////////////////////
-void DynamicTextFont::
-initialize_ft_library() {
-  if (!_ft_initialized) {
-    int error = FT_Init_FreeType(&_ft_library);
-    _ft_initialized = true;
-    if (error) {
-      text_cat.error()
-        << "Unable to initialize FreeType; DynamicTextFonts will not load.\n";
-    } else {
-      _ft_ok = true;
-    }
-  }
-}
-
 #endif  // HAVE_FREETYPE

+ 9 - 20
panda/src/text/dynamicTextFont.h

@@ -25,6 +25,7 @@
 
 #include "config_text.h"
 #include "textFont.h"
+#include "freetypeFont.h"
 #include "dynamicTextGlyph.h"
 #include "dynamicTextPage.h"
 #include "filename.h"
@@ -42,12 +43,14 @@
 //               FreeType 2.0 library (or any higher,
 //               backward-compatible version).
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA DynamicTextFont : public TextFont {
+class EXPCL_PANDA DynamicTextFont : public TextFont, public FreetypeFont {
 PUBLISHED:
   DynamicTextFont(const Filename &font_filename, int face_index = 0);
   DynamicTextFont(const char *font_data, int data_length, int face_index);
   virtual ~DynamicTextFont();
 
+  INLINE const string &get_name() const;
+
   INLINE bool set_point_size(float point_size);
   INLINE float get_point_size() const;
 
@@ -57,6 +60,9 @@ PUBLISHED:
   INLINE bool set_scale_factor(float scale_factor);
   INLINE float get_scale_factor() const;
 
+  INLINE float get_line_height() const;
+  INLINE float get_space_advance() const;
+
   INLINE void set_texture_margin(int texture_margin);
   INLINE int get_texture_margin() const;
   INLINE void set_poly_margin(float poly_margin);
@@ -91,19 +97,11 @@ public:
 private:
   void initialize();
   void update_filters();
-  bool reset_scale();
   DynamicTextGlyph *make_glyph(int glyph_index);
   void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
-  void copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image);
   void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
   DynamicTextGlyph *slot_glyph(int x_size, int y_size);
 
-  static void initialize_ft_library();
-
-  float _point_size;
-  float _tex_pixels_per_unit;
-  float _scale_factor;
-  float _font_pixels_per_unit;
   int _texture_margin;
   float _poly_margin;
   int _page_x_size, _page_y_size;
@@ -129,17 +127,6 @@ private:
   typedef pvector< PT(DynamicTextGlyph) > EmptyGlyphs;
   EmptyGlyphs _empty_glyphs;
 
-  FT_Face _face;
-
-  // This string is used to hold the data read from the font file in
-  // vfs mode.  Since the FreeType library keeps pointers into this
-  // data, we have to keep it around.
-  string _raw_font_data;
-
-  static FT_Library _ft_library;
-  static bool _ft_initialized;
-  static bool _ft_ok;
-
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
@@ -160,6 +147,8 @@ private:
   friend class TextNode;
 };
 
+INLINE ostream &operator << (ostream &out, const DynamicTextFont &dtf);
+
 #include "dynamicTextFont.I"
 
 #endif  // HAVE_FREETYPE