Browse Source

TextFont::make_copy()

David Rose 15 years ago
parent
commit
6a7580ca45

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

@@ -9,7 +9,7 @@
 
   #define TARGET pnmtext
   #define LOCAL_LIBS \
-    pnmimage putil linmath
+    pnmimage putil linmath pipeline
     
   #define SOURCES \
     config_pnmtext.cxx config_pnmtext.h \

+ 0 - 22
panda/src/pnmtext/freetypeFace.I

@@ -12,25 +12,3 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////
-//     Function: FreetypeFace::get_face
-//       Access: Published
-//  Description: Retrieves the internal freetype face.
-////////////////////////////////////////////////////////////////////
-INLINE FT_Face FreetypeFace::
-get_face() {
-  return _face;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FreetypeFace::set_face
-//       Access: Published
-//  Description: Sets the internal freetype face.
-////////////////////////////////////////////////////////////////////
-INLINE void FreetypeFace::
-set_face(FT_Face face) {
-  if (_face != NULL){
-    FT_Done_Face(_face);
-  }
-  _face = face;
-}

+ 142 - 1
panda/src/pnmtext/freetypeFace.cxx

@@ -16,6 +16,12 @@
 
 #ifdef HAVE_FREETYPE
 
+#include "config_pnmtext.h"
+
+FT_Library FreetypeFace::_ft_library;
+bool FreetypeFace::_ft_initialized = false;
+bool FreetypeFace::_ft_ok = false;
+
 TypeHandle FreetypeFace::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
@@ -24,8 +30,16 @@ TypeHandle FreetypeFace::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 FreetypeFace::
-FreetypeFace() {
+FreetypeFace() : _lock("FreetypeFace::_lock") {
   _face = NULL;
+  _char_size = 0;
+  _dpi = 0;
+  _pixel_width = 0;
+  _pixel_height = 0;
+
+  if (!_ft_initialized) {
+    initialize_ft_library();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -40,4 +54,131 @@ FreetypeFace::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFace::acquire_face
+//       Access: Public
+//  Description: Retrieves the internal freetype face, and also
+//               acquires the lock.  The freetype face is set to the
+//               indicated size, either as a char_size and dpi, or as
+//               a specific pixel_width and height, before returning.
+//
+//               You must call release_face() when you are done using
+//               it, to release the lock.
+////////////////////////////////////////////////////////////////////
+FT_Face FreetypeFace::
+acquire_face(int char_size, int dpi, int pixel_width, int pixel_height) {
+  _lock.acquire();
+
+  if (pixel_height != 0) {
+    if (pixel_height != _pixel_height || pixel_width != _pixel_width) {
+      _char_size = 0;
+      _dpi = 0;
+      _pixel_height = pixel_height;
+      _pixel_width = pixel_width;
+      FT_Set_Pixel_Sizes(_face, _pixel_width, _pixel_height);
+    }
+  } else {
+    if (char_size != _char_size || dpi != _dpi) {
+      _char_size = char_size;
+      _dpi = dpi;
+      _pixel_height = 0;
+      _pixel_width = 0;
+      if (_char_size != 0) {
+        FT_Set_Char_Size(_face, _char_size, _char_size, _dpi, _dpi);
+      }
+    }
+  }
+
+  return _face;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFace::release_face
+//       Access: Public
+//  Description: Releases the lock acquired by a previous call to
+//               acquire_face(), and allows another thread to use the
+//               face.
+////////////////////////////////////////////////////////////////////
+void FreetypeFace::
+release_face(FT_Face face) {
+  nassertv(_face == face);
+  _lock.release();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFace::set_face
+//       Access: Public
+//  Description: Replaces the internal freetype face.
+////////////////////////////////////////////////////////////////////
+void FreetypeFace::
+set_face(FT_Face face) {
+  MutexHolder holder(_lock);
+
+  if (_face != NULL){
+    FT_Done_Face(_face);
+  }
+  _face = face;
+  _char_size = 0;
+  _dpi = 0;
+  _pixel_width = 0;
+  _pixel_height = 0;
+
+  _name = _face->family_name;
+  if (_face->style_name != NULL) {
+    _name += " ";
+    _name += _face->style_name;
+  }
+  
+  pnmtext_cat.info()
+    << "Loaded font " << _name << "\n";
+
+  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]);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFace::initialize_ft_library
+//       Access: Private, Static
+//  Description: Should be called exactly once to initialize the
+//               FreeType library.
+////////////////////////////////////////////////////////////////////
+void FreetypeFace::
+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

+ 25 - 9
panda/src/pnmtext/freetypeFace.h

@@ -19,13 +19,10 @@
 
 #ifdef HAVE_FREETYPE
 
-//#include "config_pnmtext.h"
-//#include "filename.h"
-//#include "pvector.h"
-//#include "pmap.h"
-//#include "pnmImage.h"
 #include "typedReferenceCount.h"
 #include "namable.h"
+#include "pmutex.h"
+#include "mutexHolder.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
@@ -40,16 +37,33 @@
 class EXPCL_PANDA_PNMTEXT FreetypeFace : public TypedReferenceCount, public Namable {
 public:
   FreetypeFace();
-
-PUBLISHED:
   ~FreetypeFace();
 
-  INLINE FT_Face get_face();
-  INLINE void set_face(FT_Face face);
+  FT_Face acquire_face();
+  FT_Face acquire_face(int char_size, int dpi, int pixel_width, int pixel_height);
+  void release_face(FT_Face face);
+
+  void set_face(FT_Face face);
+
+private:
+  static void initialize_ft_library();
 
 private:
+  // This is provided as a permanent storage for the raw font data, if
+  // needed.
+  string _font_data;
+
+  string _name;
   FT_Face _face;
+  int _char_size;
+  int _dpi;
+  int _pixel_width;
+  int _pixel_height;
+  Mutex _lock;
 
+  static FT_Library _ft_library;
+  static bool _ft_initialized;
+  static bool _ft_ok;
 
 public:
   static TypeHandle get_class_type() {
@@ -67,6 +81,8 @@ public:
 
 private:
   static TypeHandle _type_handle;
+
+  friend class FreetypeFont;
 };
 
 

+ 29 - 1
panda/src/pnmtext/freetypeFont.I

@@ -185,7 +185,7 @@ get_native_antialias() const {
 ////////////////////////////////////////////////////////////////////
 INLINE int FreetypeFont::
 get_font_pixel_size() const {
-  return _font_pixel_size;
+  return _pixel_height;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -231,3 +231,31 @@ INLINE float FreetypeFont::
 get_points_per_inch() {
   return _points_per_inch;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::acquire_face
+//       Access: Protected
+//  Description: Retrieves the internal freetype face, and also
+//               acquires the lock.
+//
+//               You must call release_face() when you are done using
+//               it, to release the lock.
+////////////////////////////////////////////////////////////////////
+INLINE FT_Face FreetypeFont::
+acquire_face() const {
+  nassertr(_face != NULL, NULL);
+  return _face->acquire_face(_char_size, _dpi, _pixel_width, _pixel_height);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::release_face
+//       Access: Protected
+//  Description: Releases the lock acquired by a previous call to
+//               acquire_face(), and allows another thread to use the
+//               face.
+////////////////////////////////////////////////////////////////////
+INLINE void FreetypeFont::
+release_face(FT_Face face) const {
+  nassertv(_face != NULL);
+  _face->release_face(face);
+}

+ 86 - 122
panda/src/pnmtext/freetypeFont.cxx

@@ -21,10 +21,6 @@
 #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.
@@ -40,8 +36,6 @@ const float FreetypeFont::_points_per_inch = 72.0f;
 ////////////////////////////////////////////////////////////////////
 FreetypeFont::
 FreetypeFont() {
-  _font_loaded = false;
-
   _face = NULL;
 
   _point_size = text_point_size;
@@ -51,13 +45,37 @@ FreetypeFont() {
   _scale_factor = text_scale_factor;
   _native_antialias = text_native_antialias;
 
-  _font_pixel_size = 0;
   _line_height = 1.0f;
   _space_advance = 0.25f;
 
-  if (!_ft_initialized) {
-    initialize_ft_library();
-  }
+  _char_size = 0;
+  _dpi = 0;
+  _pixel_width = 0;
+  _pixel_height = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FreetypeFont::Copy Constructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FreetypeFont::
+FreetypeFont(const FreetypeFont &copy) :
+  Namable(copy),
+  _face(copy._face),
+  _point_size(copy._point_size),
+  _requested_pixels_per_unit(copy._requested_pixels_per_unit),
+  _tex_pixels_per_unit(copy._tex_pixels_per_unit),
+  _requested_scale_factor(copy._requested_scale_factor),
+  _scale_factor(copy._scale_factor),
+  _native_antialias(copy._native_antialias),
+  _line_height(copy._line_height),
+  _space_advance(copy._space_advance),
+  _char_size(copy._char_size),
+  _dpi(copy._dpi),
+  _pixel_width(copy._pixel_width),
+  _pixel_height(copy._pixel_height)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -70,31 +88,32 @@ FreetypeFont() {
 ////////////////////////////////////////////////////////////////////
 bool FreetypeFont::
 load_font(const Filename &font_filename, int face_index) {
-  if (!_ft_ok) {
+  unload_font();
+  _face = new FreetypeFace;
+  if (!_face->_ft_ok) {
     pnmtext_cat.error()
       << "Unable to read font " << font_filename
       << ": FreeType library not initialized properly.\n";
+    unload_font();
     return false;
   }
 
-  unload_font();
-
   bool exists = false;
   int error;
   Filename path(font_filename);
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   vfs->resolve_filename(path, get_model_path());
-  exists = vfs->read_file(path, _raw_font_data, true);
+  exists = vfs->read_file(path, _face->_font_data, true);
   if (exists) {
     FT_Face face;
-    error = FT_New_Memory_Face(_ft_library, 
-                               (const FT_Byte *)_raw_font_data.data(),
-                               _raw_font_data.length(),
+    error = FT_New_Memory_Face(_face->_ft_library, 
+                               (const FT_Byte *)_face->_font_data.data(),
+                               _face->_font_data.length(),
                                face_index, &face);
-    _face = new FreetypeFace();
     _face->set_face(face);
   }
 
+  bool okflag = false;
   if (!exists) {
     pnmtext_cat.error()
       << "Unable to find font file " << font_filename << "\n";
@@ -107,11 +126,15 @@ load_font(const Filename &font_filename, int face_index) {
         << "Unable to read font " << font_filename << ": invalid.\n";
 
     } else {
-      return font_loaded();
+      okflag = reset_scale();
     }
   }
+
+  if (!okflag) {
+    unload_font();
+  }
   
-  return false;
+  return okflag;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -123,22 +146,24 @@ load_font(const Filename &font_filename, int face_index) {
 ////////////////////////////////////////////////////////////////////
 bool FreetypeFont::
 load_font(const char *font_data, int data_length, int face_index) {
-  if (!_ft_ok) {
+  unload_font();
+  _face = new FreetypeFace;
+
+  if (!_face->_ft_ok) {
     pnmtext_cat.error()
       << "Unable to read font: FreeType library not initialized properly.\n";
+    unload_font();
     return false;
   }
 
-  unload_font();
-
   int error;
   FT_Face face;
-  error = FT_New_Memory_Face(_ft_library, 
+  error = FT_New_Memory_Face(_face->_ft_library, 
                              (const FT_Byte *)font_data, data_length,
                              face_index, &face);
-  _face = new FreetypeFace();
   _face->set_face(face);
 
+  bool okflag = false;
   if (error == FT_Err_Unknown_File_Format) {
     pnmtext_cat.error()
       << "Unable to read font: unknown file format.\n";
@@ -147,10 +172,14 @@ load_font(const char *font_data, int data_length, int face_index) {
       << "Unable to read font: invalid.\n";
     
   } else {
-    return font_loaded();
+    okflag = reset_scale();
   }
 
-  return false;
+  if (!okflag) {
+    unload_font();
+  }
+  
+  return okflag;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -160,10 +189,7 @@ load_font(const char *font_data, int data_length, int face_index) {
 ////////////////////////////////////////////////////////////////////
 void FreetypeFont::
 unload_font() {
-  if (_font_loaded) {
-    _face = NULL;
-    _font_loaded = false;
-  }
+  _face = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -174,7 +200,7 @@ unload_font() {
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool FreetypeFont::
-load_glyph(int glyph_index, bool prerender) {
+load_glyph(FT_Face face, int glyph_index, bool prerender) {
   int flags = FT_LOAD_RENDER;
   if (!_native_antialias) { 
     flags |= FT_LOAD_MONOCHROME;
@@ -186,7 +212,7 @@ load_glyph(int glyph_index, bool prerender) {
     flags = 0;
   }
 
-  int error = FT_Load_Glyph(_face->get_face(), glyph_index, flags);
+  int error = FT_Load_Glyph(face, glyph_index, flags);
   if (error) {
     pnmtext_cat.error()
       << "Unable to render glyph " << glyph_index << "\n";
@@ -256,57 +282,6 @@ copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image) {
       << "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->get_face()->family_name;
-  if (_face->get_face()->style_name != NULL) {
-    name += " ";
-    name += _face->get_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->get_face()->num_charmaps << " charmaps:\n";
-    for (int i = 0; i < _face->get_face()->num_charmaps; i++) {
-      pnmtext_cat.debug(false) << " " << (void *)_face->get_face()->charmaps[i];
-    }
-    pnmtext_cat.debug(false) << "\n";
-    pnmtext_cat.debug()
-      << "default charmap is " << (void *)_face->get_face()->charmap << "\n";
-  }
-  if (_face->get_face()->charmap == NULL) {
-    // If for some reason FreeType didn't set us up a charmap,
-    // then set it up ourselves.
-    if (_face->get_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->get_face()->num_charmaps > 1) {
-        pnmtext_cat.warning()
-          << "Arbitrarily choosing first of " 
-          << _face->get_face()->num_charmaps << " charmaps.\n";
-      }
-      FT_Set_Charmap(_face->get_face(), _face->get_face()->charmaps[0]);
-    }
-  }
-
-  return true;
-}
  
 ////////////////////////////////////////////////////////////////////
 //     Function: FreetypeFont::reset_scale
@@ -317,6 +292,14 @@ font_loaded() {
 ////////////////////////////////////////////////////////////////////
 bool FreetypeFont::
 reset_scale() {
+  if (_face == NULL) {
+    return false;
+  }
+
+  // Get the face, without requesting a particular size yet (we'll
+  // figure out the size in a second).
+  FT_Face face = _face->acquire_face(0, 0, 0, 0);
+
   // 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.
@@ -324,13 +307,13 @@ reset_scale() {
   _scale_factor = _requested_scale_factor;
   _font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
 
+  _pixel_height = 0;
+  _pixel_width = 0;
   float units_per_inch = (_points_per_inch / _points_per_unit);
-  int dpi = (int)(_font_pixels_per_unit * units_per_inch);
+  _dpi = (int)(_font_pixels_per_unit * units_per_inch);
+  _char_size = (int)(_point_size * 64);
   
-  _font_pixel_size = 0;
-  int error = FT_Set_Char_Size(_face->get_face(),
-                               (int)(_point_size * 64), (int)(_point_size * 64),
-                               dpi, dpi);
+  int error = FT_Set_Char_Size(face, _char_size, _char_size, _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 next larger
@@ -339,16 +322,16 @@ reset_scale() {
     int desired_height = (int)(_font_pixels_per_unit * _point_size / _points_per_unit + 0.5f);
     int best_size = -1;
     int largest_size = -1;
-    if (_face->get_face()->num_fixed_sizes > 0) {
+    if (face->num_fixed_sizes > 0) {
       largest_size = 0;
       int best_diff = 0;
-      for (int i = 0; i < _face->get_face()->num_fixed_sizes; i++) {
-        int diff = _face->get_face()->available_sizes[i].height - desired_height;
+      for (int i = 0; i < face->num_fixed_sizes; i++) {
+        int diff = face->available_sizes[i].height - desired_height;
         if (diff > 0 && (best_size == -1 || diff < best_diff)) {
           best_size = i;
           best_diff = diff;
         }
-        if (_face->get_face()->available_sizes[i].height > _face->get_face()->available_sizes[largest_size].height) {
+        if (face->available_sizes[i].height > face->available_sizes[largest_size].height) {
           largest_size = i;
         }
       }
@@ -358,13 +341,12 @@ reset_scale() {
     }
 
     if (best_size >= 0) {
-      int pixel_height = _face->get_face()->available_sizes[best_size].height;
-      int pixel_width = _face->get_face()->available_sizes[best_size].width;
-      error = FT_Set_Pixel_Sizes(_face->get_face(), pixel_width, pixel_height);
+      _pixel_height = face->available_sizes[best_size].height;
+      _pixel_width = face->available_sizes[best_size].width;
+      error = FT_Set_Pixel_Sizes(face, _pixel_width, _pixel_height);
       if (!error) {
-        _font_pixels_per_unit = pixel_height * _points_per_unit / _point_size;
+        _font_pixels_per_unit = _pixel_height * _points_per_unit / _point_size;
         _scale_factor = _font_pixels_per_unit / _tex_pixels_per_unit;
-        _font_pixel_size = pixel_height;
 
         if (_scale_factor < 1.0) {
           // No point in enlarging a fixed-point font.
@@ -378,44 +360,26 @@ reset_scale() {
   if (error) {
     pnmtext_cat.warning()
       << "Unable to set " << get_name() 
-      << " to " << _point_size << "pt at " << dpi << " dpi.\n";
+      << " to " << _point_size << "pt at " << _dpi << " dpi.\n";
     _line_height = 1.0f;
+    _face->release_face(face);
     return false;
   }
 
-  _line_height = _face->get_face()->size->metrics.height / (_font_pixels_per_unit * 64.0f);
+  _line_height = face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
 
   // Determine the correct width for a space.
-  error = FT_Load_Char(_face->get_face(), ' ', FT_LOAD_DEFAULT);
+  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->get_face()->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
+    _space_advance = face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
   }
 
+  _face->release_face(face);
   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

+ 9 - 14
panda/src/pnmtext/freetypeFont.h

@@ -41,6 +41,7 @@
 class EXPCL_PANDA_PNMTEXT FreetypeFont : public Namable {
 protected:
   FreetypeFont();
+  FreetypeFont(const FreetypeFont &copy);
 
   bool load_font(const Filename &font_filename, int face_index);
   bool load_font(const char *font_data, int data_length, int face_index);
@@ -73,13 +74,14 @@ PUBLISHED:
   INLINE static float get_points_per_inch();
 
 protected:
-  bool load_glyph(int glyph_index, bool prerender = true);
+  INLINE FT_Face acquire_face() const;
+  INLINE void release_face(FT_Face face) const;
+
+  bool load_glyph(FT_Face face, int glyph_index, bool prerender = true);
   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;
@@ -95,19 +97,12 @@ protected:
   float _space_advance;
 
   PT(FreetypeFace) _face;
+  int _char_size;
+  int _dpi;
+  int _pixel_width;
+  int _pixel_height;
 
 protected:
-  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;
 };

+ 29 - 7
panda/src/pnmtext/pnmTextMaker.cxx

@@ -43,6 +43,22 @@ PNMTextMaker(const char *font_data, int data_length, int face_index) {
   _is_valid = load_font(font_data, data_length, face_index);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMTextMaker::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PNMTextMaker::
+PNMTextMaker(const PNMTextMaker &copy) :
+  FreetypeFont(copy),
+  _is_valid(copy._is_valid),
+  _align(copy._align),
+  _interior_flag(copy._interior_flag),
+  _fg(copy._fg),
+  _interior(copy._interior)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMTextMaker::Destructor
 //       Access: Public
@@ -124,7 +140,9 @@ calc_width(const wstring &text) {
 ////////////////////////////////////////////////////////////////////
 PNMTextGlyph *PNMTextMaker::
 get_glyph(int character) {
-  int glyph_index = FT_Get_Char_Index(_face->get_face(), character);
+  FT_Face face = acquire_face();
+  int glyph_index = FT_Get_Char_Index(face, character);
+  release_face(face);
 
   Glyphs::iterator gi;
   gi = _glyphs.find(glyph_index);
@@ -159,23 +177,25 @@ initialize() {
 ////////////////////////////////////////////////////////////////////
 PNMTextGlyph *PNMTextMaker::
 make_glyph(int glyph_index) {
-  if (!load_glyph(glyph_index)) {
+  FT_Face face = acquire_face();
+  if (!load_glyph(face, glyph_index)) {
+    release_face(face);
     return (PNMTextGlyph *)NULL;
   }
 
-  FT_GlyphSlot slot = _face->get_face()->glyph;
+  FT_GlyphSlot slot = face->glyph;
+
   FT_Bitmap &bitmap = slot->bitmap;
 
   double advance = slot->advance.x / 64.0;
 
+  PNMTextGlyph *glyph = new PNMTextGlyph(advance);
+
   if (bitmap.width == 0 || bitmap.rows == 0) {
     // If we got an empty bitmap, it's a special case.
-    PNMTextGlyph *glyph = new PNMTextGlyph(advance);
     glyph->rescale(_scale_factor);
-    return glyph;
 
   } else {
-    PNMTextGlyph *glyph = new PNMTextGlyph(advance);
     PNMImage &glyph_image = glyph->_image;
     glyph_image.clear(bitmap.width, bitmap.rows, 3);
     copy_bitmap_to_pnmimage(bitmap, glyph_image);
@@ -187,8 +207,10 @@ make_glyph(int glyph_index) {
       glyph->determine_interior();
     }
     glyph->rescale(_scale_factor);
-    return glyph;
   }
+
+  release_face(face);
+  return glyph;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/pnmtext/pnmTextMaker.h

@@ -40,6 +40,7 @@ class EXPCL_PANDA_PNMTEXT PNMTextMaker : public FreetypeFont {
 PUBLISHED:
   PNMTextMaker(const Filename &font_filename, int face_index);
   PNMTextMaker(const char *font_data, int data_length, int face_index);
+  PNMTextMaker(const PNMTextMaker &copy);
   ~PNMTextMaker();
 
   enum Alignment {

+ 52 - 8
panda/src/text/dynamicTextFont.cxx

@@ -99,6 +99,36 @@ DynamicTextFont(const char *font_data, int data_length, int face_index) {
   _needs_image_processing = false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DynamicTextFont::
+DynamicTextFont(const DynamicTextFont &copy) :
+  TextFont(copy),
+  FreetypeFont(copy),
+  _texture_margin(copy._texture_margin),
+  _poly_margin(copy._poly_margin),
+  _page_x_size(copy._page_x_size),
+  _page_y_size(copy._page_y_size),
+  _minfilter(copy._minfilter),
+  _magfilter(copy._magfilter),
+  _anisotropic_degree(copy._anisotropic_degree),
+  _render_mode(copy._render_mode),
+  _winding_order(copy._winding_order),
+  _fg(copy._fg),
+  _bg(copy._bg),
+  _outline_color(copy._outline_color),
+  _outline_width(copy._outline_width),
+  _outline_feather(copy._outline_feather),
+  _has_outline(copy._has_outline),
+  _tex_format(copy._tex_format),
+  _needs_image_processing(copy._needs_image_processing),
+  _preferred_page(0)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::Destructor
 //       Access: Published, Virtual
@@ -108,6 +138,16 @@ DynamicTextFont::
 ~DynamicTextFont() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DynamicTextFont::make_copy
+//       Access: Published
+//  Description: Returns a new copy of the same font.
+////////////////////////////////////////////////////////////////////
+PT(TextFont) DynamicTextFont::
+make_copy() const {
+  return new DynamicTextFont(*this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextFont::get_num_pages
 //       Access: Published
@@ -216,8 +256,9 @@ write(ostream &out, int indent_level) const {
     indent(out, indent_level + 2) 
       << glyph_index;
 
-    if (FT_HAS_GLYPH_NAMES(_face->get_face())) {
-      int error = FT_Get_Glyph_Name(_face->get_face(), glyph_index, 
+    FT_Face face = acquire_face();
+    if (FT_HAS_GLYPH_NAMES(face)) {
+      int error = FT_Get_Glyph_Name(face, glyph_index, 
                                     glyph_name, max_glyph_name);
 
       // Some fonts, notably MS Mincho, claim to have glyph names but
@@ -226,6 +267,7 @@ write(ostream &out, int indent_level) const {
         out << " (" << glyph_name << ")";
       }
     }
+    release_face(face);
 
     out << ", count = " << glyph->_geom_count << "\n";
   }
@@ -249,7 +291,8 @@ get_glyph(int character, const TextGlyph *&glyph) {
     return false;
   }
 
-  int glyph_index = FT_Get_Char_Index(_face->get_face(), character);
+  FT_Face face = acquire_face();
+  int glyph_index = FT_Get_Char_Index(face, character);
   if (text_cat.is_spam()) {
     text_cat.spam()
       << *this << " maps " << character << " to glyph " << glyph_index << "\n";
@@ -259,7 +302,7 @@ get_glyph(int character, const TextGlyph *&glyph) {
   if (ci != _cache.end()) {
     glyph = (*ci).second;
   } else {
-    DynamicTextGlyph *dynamic_glyph = make_glyph(character, glyph_index);
+    DynamicTextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
     _cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
     glyph = dynamic_glyph;
   }
@@ -269,6 +312,7 @@ get_glyph(int character, const TextGlyph *&glyph) {
     glyph_index = 0;
   }
     
+  release_face(face);
   return (glyph_index != 0);
 }
 
@@ -399,12 +443,12 @@ determine_tex_format() {
 //               glyph cannot be created for some reason.
 ////////////////////////////////////////////////////////////////////
 DynamicTextGlyph *DynamicTextFont::
-make_glyph(int character, int glyph_index) {
-  if (!load_glyph(glyph_index, false)) {
+make_glyph(int character, FT_Face face, int glyph_index) {
+  if (!load_glyph(face, glyph_index, false)) {
     return (DynamicTextGlyph *)NULL;
   }
 
-  FT_GlyphSlot slot = _face->get_face()->glyph;
+  FT_GlyphSlot slot = face->glyph;
   FT_Bitmap &bitmap = slot->bitmap;
 
   if ((bitmap.width == 0 || bitmap.rows == 0) && (glyph_index == 0)) {
@@ -423,7 +467,7 @@ make_glyph(int character, int glyph_index) {
     // Re-stroke the glyph to make it an outline glyph.
     /*
     FT_Stroker stroker;
-    FT_Stroker_New(_face->get_face()->memory, &stroker);
+    FT_Stroker_New(face->memory, &stroker);
     FT_Stroker_Set(stroker, 16 * 16, FT_STROKER_LINECAP_BUTT,
                    FT_STROKER_LINEJOIN_ROUND, 0);
 

+ 4 - 1
panda/src/text/dynamicTextFont.h

@@ -44,8 +44,11 @@ class EXPCL_PANDA_TEXT 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);
+  DynamicTextFont(const DynamicTextFont &copy);
   virtual ~DynamicTextFont();
 
+  virtual PT(TextFont) make_copy() const;
+
   INLINE const string &get_name() const;
 
   INLINE bool set_point_size(float point_size);
@@ -113,7 +116,7 @@ private:
   void initialize();
   void update_filters();
   void determine_tex_format();
-  DynamicTextGlyph *make_glyph(int character, int glyph_index);
+  DynamicTextGlyph *make_glyph(int character, FT_Face face, int glyph_index);
   void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
   void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
   void blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,

+ 10 - 0
panda/src/text/staticTextFont.cxx

@@ -74,6 +74,16 @@ StaticTextFont(PandaNode *font_def) {
   set_name(font_def->get_name());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: StaticTextFont::make_copy
+//       Access: Published
+//  Description: Returns a new copy of the same font.
+////////////////////////////////////////////////////////////////////
+PT(TextFont) StaticTextFont::
+make_copy() const {
+  return new StaticTextFont(_font);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: StaticTextFont::write
 //       Access: Published, Virtual

+ 2 - 0
panda/src/text/staticTextFont.h

@@ -41,6 +41,8 @@ class EXPCL_PANDA_TEXT StaticTextFont : public TextFont {
 PUBLISHED:
   StaticTextFont(PandaNode *font_def);
 
+  virtual PT(TextFont) make_copy() const;
+
   virtual void write(ostream &out, int indent_level) const;
 
 public:

+ 14 - 0
panda/src/text/textFont.cxx

@@ -36,6 +36,20 @@ TextFont() {
   _space_advance = 0.25f;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextFont::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+TextFont::
+TextFont(const TextFont &copy) :
+  Namable(copy),
+  _is_valid(copy._is_valid),
+  _line_height(copy._line_height),
+  _space_advance(copy._space_advance)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextFont::Destructor
 //       Access: Published, Virtual

+ 2 - 0
panda/src/text/textFont.h

@@ -36,6 +36,7 @@
 class EXPCL_PANDA_TEXT TextFont : public TypedReferenceCount, public Namable {
 public:
   TextFont();
+  TextFont(const TextFont &copy);
 
 PUBLISHED:
   virtual ~TextFont();
@@ -68,6 +69,7 @@ PUBLISHED:
     WO_invalid,
   };
 
+  virtual PT(TextFont) make_copy() const=0;
 
   INLINE bool is_valid() const;
   INLINE operator bool () const;