Panda3D
|
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 }