Panda3D
fontPool.cxx
1 // Filename: fontPool.cxx
2 // Created by: drose (31Jan03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "fontPool.h"
16 #include "staticTextFont.h"
17 #include "dynamicTextFont.h"
18 #include "config_util.h"
19 #include "config_express.h"
20 #include "virtualFileSystem.h"
21 #include "nodePath.h"
22 #include "loader.h"
23 #include "lightMutexHolder.h"
24 
25 FontPool *FontPool::_global_ptr = (FontPool *)NULL;
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: FontPool::write
29 // Access: Published, Static
30 // Description: Lists the contents of the font pool to the
31 // indicated output stream.
32 ////////////////////////////////////////////////////////////////////
33 void FontPool::
34 write(ostream &out) {
35  get_ptr()->ns_list_contents(out);
36 }
37 
38 ////////////////////////////////////////////////////////////////////
39 // Function: FontPool::ns_has_font
40 // Access: Private
41 // Description: The nonstatic implementation of has_font().
42 ////////////////////////////////////////////////////////////////////
43 bool FontPool::
44 ns_has_font(const string &str) {
45  LightMutexHolder holder(_lock);
46 
47  string index_str;
48  Filename filename;
49  int face_index;
50  lookup_filename(str, index_str, filename, face_index);
51 
52  Fonts::const_iterator ti;
53  ti = _fonts.find(index_str);
54  if (ti != _fonts.end()) {
55  // This font was previously loaded.
56  return true;
57  }
58 
59  return false;
60 }
61 
62 ////////////////////////////////////////////////////////////////////
63 // Function: FontPool::ns_load_font
64 // Access: Private
65 // Description: The nonstatic implementation of load_font().
66 ////////////////////////////////////////////////////////////////////
67 TextFont *FontPool::
68 ns_load_font(const string &str) {
69  string index_str;
70  Filename filename;
71  int face_index;
72  lookup_filename(str, index_str, filename, face_index);
73 
74  {
75  LightMutexHolder holder(_lock);
76 
77  Fonts::const_iterator ti;
78  ti = _fonts.find(index_str);
79  if (ti != _fonts.end()) {
80  // This font was previously loaded.
81  return (*ti).second;
82  }
83  }
84 
85  text_cat.info()
86  << "Loading font " << filename << "\n";
87 
88  // Now, figure out how to load the font. If its filename extension
89  // is "egg" or "bam", or if it's unspecified, assume it's a model
90  // file, representing a static font.
91  PT(TextFont) font;
92 
93  string extension = filename.get_extension();
94  if (extension.empty() || extension == "egg" || extension == "bam") {
95  Loader *model_loader = Loader::get_global_ptr();
96  PT(PandaNode) node = model_loader->load_sync(filename);
97  if (node != (PandaNode *)NULL) {
98  // It is a model. Elevate all the priorities by 1, and make a
99  // font out of it.
100 
101  // On second thought, why should we elevate the priorities? The
102  // DynamicTextFont doesn't do this, and doing so for the
103  // StaticTextFont only causes problems (it changes the default
104  // ColorAttrib from pri -1 to pri 0).
105  /*
106  NodePath np(node);
107  np.adjust_all_priorities(1);
108  */
109 
110  font = new StaticTextFont(node);
111  }
112  }
113 
114 #ifdef HAVE_FREETYPE
115  if (font == (TextFont *)NULL || !font->is_valid()) {
116  // If we couldn't load the font as a model, try using FreeType to
117  // load it as a font file.
118  font = new DynamicTextFont(filename, face_index);
119  }
120 #endif
121 
122  if (font == (TextFont *)NULL || !font->is_valid()) {
123  // This font was not found or could not be read.
124  return NULL;
125  }
126 
127 
128  {
129  LightMutexHolder holder(_lock);
130 
131  // Look again. It may have been loaded by another thread.
132  Fonts::const_iterator ti;
133  ti = _fonts.find(index_str);
134  if (ti != _fonts.end()) {
135  // This font was previously loaded.
136  return (*ti).second;
137  }
138 
139  _fonts[index_str] = font;
140  }
141 
142  return font;
143 }
144 
145 ////////////////////////////////////////////////////////////////////
146 // Function: FontPool::ns_add_font
147 // Access: Private
148 // Description: The nonstatic implementation of add_font().
149 ////////////////////////////////////////////////////////////////////
150 void FontPool::
151 ns_add_font(const string &str, TextFont *font) {
152  LightMutexHolder holder(_lock);
153 
154  string index_str;
155  Filename filename;
156  int face_index;
157  lookup_filename(str, index_str, filename, face_index);
158 
159  // We blow away whatever font was there previously, if any.
160  _fonts[index_str] = font;
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: FontPool::ns_release_font
165 // Access: Private
166 // Description: The nonstatic implementation of release_font().
167 ////////////////////////////////////////////////////////////////////
168 void FontPool::
169 ns_release_font(const string &str) {
170  LightMutexHolder holder(_lock);
171 
172  string index_str;
173  Filename filename;
174  int face_index;
175  lookup_filename(str, index_str, filename, face_index);
176 
177  Fonts::iterator ti;
178  ti = _fonts.find(index_str);
179  if (ti != _fonts.end()) {
180  _fonts.erase(ti);
181  }
182 }
183 
184 ////////////////////////////////////////////////////////////////////
185 // Function: FontPool::ns_release_all_fonts
186 // Access: Private
187 // Description: The nonstatic implementation of release_all_fonts().
188 ////////////////////////////////////////////////////////////////////
189 void FontPool::
190 ns_release_all_fonts() {
191  LightMutexHolder holder(_lock);
192 
193  _fonts.clear();
194 }
195 
196 ////////////////////////////////////////////////////////////////////
197 // Function: FontPool::ns_garbage_collect
198 // Access: Private
199 // Description: The nonstatic implementation of garbage_collect().
200 ////////////////////////////////////////////////////////////////////
201 int FontPool::
202 ns_garbage_collect() {
203  LightMutexHolder holder(_lock);
204 
205  int num_released = 0;
206  Fonts new_set;
207 
208  Fonts::iterator ti;
209  for (ti = _fonts.begin(); ti != _fonts.end(); ++ti) {
210  TextFont *font = (*ti).second;
211  if (font->get_ref_count() == 1) {
212  if (text_cat.is_debug()) {
213  text_cat.debug()
214  << "Releasing " << (*ti).first << "\n";
215  }
216  num_released++;
217  } else {
218  new_set.insert(new_set.end(), *ti);
219  }
220  }
221 
222  _fonts.swap(new_set);
223  return num_released;
224 }
225 
226 ////////////////////////////////////////////////////////////////////
227 // Function: FontPool::ns_list_contents
228 // Access: Private
229 // Description: The nonstatic implementation of list_contents().
230 ////////////////////////////////////////////////////////////////////
231 void FontPool::
232 ns_list_contents(ostream &out) const {
233  LightMutexHolder holder(_lock);
234 
235  out << _fonts.size() << " fonts:\n";
236  Fonts::const_iterator ti;
237  for (ti = _fonts.begin(); ti != _fonts.end(); ++ti) {
238  TextFont *font = (*ti).second;
239  out << " " << (*ti).first
240  << " (count = " << font->get_ref_count() << ")\n";
241  }
242 }
243 
244 ////////////////////////////////////////////////////////////////////
245 // Function: FontPool::lookup_filename
246 // Access: Private, Static
247 // Description: Accepts a font "filename", which might consist of a
248 // filename followed by an optional colon and a face
249 // index, and splits it out into its two components.
250 // Then it looks up the filename on the model path.
251 // Sets the filename and face index accordingly. Also
252 // sets index_str to be the concatenation of the
253 // found filename with the face index, thus restoring
254 // the original input (but normalized to contain the
255 // full path.)
256 ////////////////////////////////////////////////////////////////////
257 void FontPool::
258 lookup_filename(const string &str, string &index_str,
259  Filename &filename, int &face_index) {
260  int colon = (int)str.length() - 1;
261  // Scan backwards over digits for a colon.
262  while (colon >= 0 && isdigit(str[colon])) {
263  --colon;
264  }
265  if (colon >= 0 && str[colon] == ':') {
266  string digits = str.substr(colon + 1);
267  filename = str.substr(0, colon);
268  face_index = atoi(digits.c_str());
269  } else {
270  filename = str;
271  face_index = 0;
272  }
273 
274  // Now look up the filename on the model path.
276  vfs->resolve_filename(filename, get_model_path());
277 
278  ostringstream strm;
279  strm << filename << ":" << face_index;
280  index_str = strm.str();
281 }
282 
283 ////////////////////////////////////////////////////////////////////
284 // Function: FontPool::get_ptr
285 // Access: Private, Static
286 // Description: Initializes and/or returns the global pointer to the
287 // one FontPool object in the system.
288 ////////////////////////////////////////////////////////////////////
289 FontPool *FontPool::
290 get_ptr() {
291  if (_global_ptr == (FontPool *)NULL) {
292  _global_ptr = new FontPool;
293  }
294  return _global_ptr;
295 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const string &default_extension=string()) const
Searches the given search path for the filename.
This is the preferred interface for loading fonts for the TextNode system.
Definition: fontPool.h:33
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
static void write(ostream &out)
Lists the contents of the font pool to the indicated output stream.
Definition: fontPool.cxx:34
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
Definition: loader.h:47
string get_extension() const
Returns the file extension.
Definition: filename.I:477
An encapsulation of a font; i.e.
Definition: textFont.h:36
A StaticTextFont is loaded up from a model that was previously generated via egg-mkfont, and contains all of its glyphs already generated and available for use.
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
Definition: loader.I:267
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
Similar to MutexHolder, but for a light mutex.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
bool is_valid() const
Returns true if the font is valid and ready to use, false otherwise.
Definition: textFont.I:23
int get_ref_count() const
Returns the current reference count.