Panda3D

fontPool.cxx

00001 // Filename: fontPool.cxx
00002 // Created by:  drose (31Jan03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "fontPool.h"
00016 #include "staticTextFont.h"
00017 #include "dynamicTextFont.h"
00018 #include "config_util.h"
00019 #include "config_express.h"
00020 #include "virtualFileSystem.h"
00021 #include "nodePath.h"
00022 #include "loader.h"
00023 #include "lightMutexHolder.h"
00024 
00025 FontPool *FontPool::_global_ptr = (FontPool *)NULL;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: FontPool::write
00029 //       Access: Published, Static
00030 //  Description: Lists the contents of the font pool to the
00031 //               indicated output stream.
00032 ////////////////////////////////////////////////////////////////////
00033 void FontPool::
00034 write(ostream &out) {
00035   get_ptr()->ns_list_contents(out);
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: FontPool::ns_has_font
00040 //       Access: Private
00041 //  Description: The nonstatic implementation of has_font().
00042 ////////////////////////////////////////////////////////////////////
00043 bool FontPool::
00044 ns_has_font(const string &str) {
00045   LightMutexHolder holder(_lock);
00046 
00047   string index_str;
00048   Filename filename;
00049   int face_index;
00050   lookup_filename(str, index_str, filename, face_index);
00051 
00052   Fonts::const_iterator ti;
00053   ti = _fonts.find(index_str);
00054   if (ti != _fonts.end()) {
00055     // This font was previously loaded.
00056     return true;
00057   }
00058 
00059   return false;
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: FontPool::ns_load_font
00064 //       Access: Private
00065 //  Description: The nonstatic implementation of load_font().
00066 ////////////////////////////////////////////////////////////////////
00067 TextFont *FontPool::
00068 ns_load_font(const string &str) {
00069   string index_str;
00070   Filename filename;
00071   int face_index;
00072   lookup_filename(str, index_str, filename, face_index);
00073 
00074   {
00075     LightMutexHolder holder(_lock);
00076     
00077     Fonts::const_iterator ti;
00078     ti = _fonts.find(index_str);
00079     if (ti != _fonts.end()) {
00080       // This font was previously loaded.
00081       return (*ti).second;
00082     }
00083   }
00084 
00085   text_cat.info()
00086     << "Loading font " << filename << "\n";
00087 
00088   // Now, figure out how to load the font.  If its filename extension
00089   // is "egg" or "bam", or if it's unspecified, assume it's a model
00090   // file, representing a static font.
00091   PT(TextFont) font;
00092 
00093   string extension = filename.get_extension();
00094   if (extension.empty() || extension == "egg" || extension == "bam") {
00095     Loader *model_loader = Loader::get_global_ptr();
00096     PT(PandaNode) node = model_loader->load_sync(filename);
00097     if (node != (PandaNode *)NULL) {
00098       // It is a model.  Elevate all the priorities by 1, and make a
00099       // font out of it.
00100 
00101       // On second thought, why should we elevate the priorities?  The
00102       // DynamicTextFont doesn't do this, and doing so for the
00103       // StaticTextFont only causes problems (it changes the default
00104       // ColorAttrib from pri -1 to pri 0).
00105       /*
00106       NodePath np(node);
00107       np.adjust_all_priorities(1);
00108       */
00109 
00110       font = new StaticTextFont(node);
00111     }
00112   }
00113 
00114 #ifdef HAVE_FREETYPE
00115   if (font == (TextFont *)NULL || !font->is_valid()) {
00116     // If we couldn't load the font as a model, try using FreeType to
00117     // load it as a font file.
00118     font = new DynamicTextFont(filename, face_index);
00119   }
00120 #endif
00121 
00122   if (font == (TextFont *)NULL || !font->is_valid()) {
00123     // This font was not found or could not be read.
00124     return NULL;
00125   }
00126 
00127 
00128   {
00129     LightMutexHolder holder(_lock);
00130 
00131     // Look again.  It may have been loaded by another thread.
00132     Fonts::const_iterator ti;
00133     ti = _fonts.find(index_str);
00134     if (ti != _fonts.end()) {
00135       // This font was previously loaded.
00136       return (*ti).second;
00137     }
00138 
00139     _fonts[index_str] = font;
00140   }
00141 
00142   return font;
00143 }
00144 
00145 ////////////////////////////////////////////////////////////////////
00146 //     Function: FontPool::ns_add_font
00147 //       Access: Private
00148 //  Description: The nonstatic implementation of add_font().
00149 ////////////////////////////////////////////////////////////////////
00150 void FontPool::
00151 ns_add_font(const string &str, TextFont *font) {
00152   LightMutexHolder holder(_lock);
00153 
00154   string index_str;
00155   Filename filename;
00156   int face_index;
00157   lookup_filename(str, index_str, filename, face_index);
00158 
00159   // We blow away whatever font was there previously, if any.
00160   _fonts[index_str] = font;
00161 }
00162 
00163 ////////////////////////////////////////////////////////////////////
00164 //     Function: FontPool::ns_release_font
00165 //       Access: Private
00166 //  Description: The nonstatic implementation of release_font().
00167 ////////////////////////////////////////////////////////////////////
00168 void FontPool::
00169 ns_release_font(const string &str) {
00170   LightMutexHolder holder(_lock);
00171 
00172   string index_str;
00173   Filename filename;
00174   int face_index;
00175   lookup_filename(str, index_str, filename, face_index);
00176 
00177   Fonts::iterator ti;
00178   ti = _fonts.find(index_str);
00179   if (ti != _fonts.end()) {
00180     _fonts.erase(ti);
00181   }
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: FontPool::ns_release_all_fonts
00186 //       Access: Private
00187 //  Description: The nonstatic implementation of release_all_fonts().
00188 ////////////////////////////////////////////////////////////////////
00189 void FontPool::
00190 ns_release_all_fonts() {
00191   LightMutexHolder holder(_lock);
00192 
00193   _fonts.clear();
00194 }
00195 
00196 ////////////////////////////////////////////////////////////////////
00197 //     Function: FontPool::ns_garbage_collect
00198 //       Access: Private
00199 //  Description: The nonstatic implementation of garbage_collect().
00200 ////////////////////////////////////////////////////////////////////
00201 int FontPool::
00202 ns_garbage_collect() {
00203   LightMutexHolder holder(_lock);
00204 
00205   int num_released = 0;
00206   Fonts new_set;
00207 
00208   Fonts::iterator ti;
00209   for (ti = _fonts.begin(); ti != _fonts.end(); ++ti) {
00210     TextFont *font = (*ti).second;
00211     if (font->get_ref_count() == 1) {
00212       if (text_cat.is_debug()) {
00213         text_cat.debug()
00214           << "Releasing " << (*ti).first << "\n";
00215       }
00216       num_released++;
00217     } else {
00218       new_set.insert(new_set.end(), *ti);
00219     }
00220   }
00221 
00222   _fonts.swap(new_set);
00223   return num_released;
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: FontPool::ns_list_contents
00228 //       Access: Private
00229 //  Description: The nonstatic implementation of list_contents().
00230 ////////////////////////////////////////////////////////////////////
00231 void FontPool::
00232 ns_list_contents(ostream &out) const {
00233   LightMutexHolder holder(_lock);
00234 
00235   out << _fonts.size() << " fonts:\n";
00236   Fonts::const_iterator ti;
00237   for (ti = _fonts.begin(); ti != _fonts.end(); ++ti) {
00238     TextFont *font = (*ti).second;
00239     out << "  " << (*ti).first
00240         << " (count = " << font->get_ref_count() << ")\n";
00241   }
00242 }
00243 
00244 ////////////////////////////////////////////////////////////////////
00245 //     Function: FontPool::lookup_filename
00246 //       Access: Private, Static
00247 //  Description: Accepts a font "filename", which might consist of a
00248 //               filename followed by an optional colon and a face
00249 //               index, and splits it out into its two components.
00250 //               Then it looks up the filename on the model path.
00251 //               Sets the filename and face index accordingly.  Also
00252 //               sets index_str to be the concatenation of the
00253 //               found filename with the face index, thus restoring
00254 //               the original input (but normalized to contain the
00255 //               full path.)
00256 ////////////////////////////////////////////////////////////////////
00257 void FontPool::
00258 lookup_filename(const string &str, string &index_str,
00259                 Filename &filename, int &face_index) {
00260   int colon = (int)str.length() - 1;
00261   // Scan backwards over digits for a colon.
00262   while (colon >= 0 && isdigit(str[colon])) {
00263     --colon;
00264   }
00265   if (colon >= 0 && str[colon] == ':') {
00266     string digits = str.substr(colon + 1);
00267     filename = str.substr(0, colon);
00268     face_index = atoi(digits.c_str());
00269   } else {
00270     filename = str;
00271     face_index = 0;
00272   }
00273 
00274   // Now look up the filename on the model path.
00275   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00276   vfs->resolve_filename(filename, get_model_path());
00277 
00278   ostringstream strm;
00279   strm << filename << ":" << face_index;
00280   index_str = strm.str();
00281 }
00282 
00283 ////////////////////////////////////////////////////////////////////
00284 //     Function: FontPool::get_ptr
00285 //       Access: Private, Static
00286 //  Description: Initializes and/or returns the global pointer to the
00287 //               one FontPool object in the system.
00288 ////////////////////////////////////////////////////////////////////
00289 FontPool *FontPool::
00290 get_ptr() {
00291   if (_global_ptr == (FontPool *)NULL) {
00292     _global_ptr = new FontPool;
00293   }
00294   return _global_ptr;
00295 }
 All Classes Functions Variables Enumerations