Panda3D
modelPool.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file modelPool.cxx
10  * @author drose
11  * @date 2002-03-12
12  */
13 
14 #include "modelPool.h"
15 #include "loader.h"
16 #include "config_pgraph.h"
17 #include "lightMutexHolder.h"
18 #include "virtualFileSystem.h"
19 
20 
21 ModelPool *ModelPool::_global_ptr = nullptr;
22 
23 /**
24  * Lists the contents of the model pool to the indicated output stream. Helps
25  * with debugging.
26  */
27 void ModelPool::
28 write(std::ostream &out) {
29  get_ptr()->ns_list_contents(out);
30 }
31 
32 /**
33  * The nonstatic implementation of has_model().
34  */
35 bool ModelPool::
36 ns_has_model(const Filename &filename) {
37  LightMutexHolder holder(_lock);
38  Models::const_iterator ti;
39  ti = _models.find(filename);
40  if (ti != _models.end() && (*ti).second != nullptr) {
41  // This model was previously loaded.
42  return true;
43  }
44 
45  return false;
46 }
47 
48 /**
49  * The nonstatic implementation of get_model().
50  */
51 ModelRoot *ModelPool::
52 ns_get_model(const Filename &filename, bool verify) {
53 
54  PT(ModelRoot) cached_model;
55  bool got_cached_model = false;
56 
57  {
58  LightMutexHolder holder(_lock);
59  Models::const_iterator ti;
60  ti = _models.find(filename);
61  if (ti != _models.end()) {
62  // This filename was previously loaded.
63  cached_model = (*ti).second;
64  got_cached_model = true;
65  }
66  }
67 
68  if (got_cached_model && verify) {
69  if (pgraph_cat.is_debug()) {
70  pgraph_cat.debug()
71  << "ModelPool found " << cached_model << " for " << filename << "\n";
72  }
73 
74  if (cached_model == nullptr) {
75  // This filename was previously attempted, but it did not exist (or the
76  // model could not be loaded for some reason).
77  if (cache_check_timestamps) {
78  // Check to see if there is a file there now.
80  if (vfs->exists(filename)) {
81  // There is, so try to load it.
82  got_cached_model = false;
83  }
84  }
85  } else {
86  // This filename was previously attempted, and successfully loaded.
87  if (cache_check_timestamps && cached_model->get_timestamp() != 0 &&
88  !cached_model->get_fullpath().empty()) {
89  // Compare the timestamp to the file on-disk.
91  PT(VirtualFile) vfile = vfs->get_file(cached_model->get_fullpath());
92  if (vfile == nullptr) {
93  // The file has disappeared! Look further along the model-path.
94  got_cached_model = false;
95 
96  } else if (vfile->get_timestamp() > cached_model->get_timestamp()) {
97  // The file still exists, but it has a newer timestamp than the one
98  // we previously loaded. Force it to re-load.
99  got_cached_model = false;
100  }
101  }
102  }
103  }
104 
105  if (got_cached_model) {
106  if (pgraph_cat.is_debug()) {
107  pgraph_cat.debug()
108  << "ModelPool returning " << cached_model << " for " << filename << "\n";
109  }
110  return cached_model;
111  } else {
112  return nullptr;
113  }
114 }
115 
116 /**
117  * The nonstatic implementation of load_model().
118  */
119 ModelRoot *ModelPool::
120 ns_load_model(const Filename &filename, const LoaderOptions &options) {
121 
122  // First check if it has already been loaded and is still current.
123  PT(ModelRoot) cached_model = ns_get_model(filename, true);
124  if (cached_model != nullptr) {
125  return cached_model;
126  }
127 
128  // Look on disk for the current file.
129  LoaderOptions new_options(options);
130  new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) &
131  ~LoaderOptions::LF_search);
132 
133  Loader *model_loader = Loader::get_global_ptr();
134  PT(PandaNode) panda_node = model_loader->load_sync(filename, new_options);
135  PT(ModelRoot) node;
136 
137  if (panda_node.is_null()) {
138  // This model was not found.
139 
140  } else {
141  if (panda_node->is_of_type(ModelRoot::get_class_type())) {
142  node = DCAST(ModelRoot, panda_node);
143 
144  } else {
145  // We have to construct a ModelRoot node to put it under.
146  node = new ModelRoot(filename);
147  node->add_child(panda_node);
148  }
149  node->set_fullpath(filename);
150  }
151 
152  {
153  LightMutexHolder holder(_lock);
154 
155  // Look again, in case someone has just loaded the model in another
156  // thread.
157  Models::const_iterator ti;
158  ti = _models.find(filename);
159  if (ti != _models.end() && (*ti).second != cached_model) {
160  // This model was previously loaded.
161  return (*ti).second;
162  }
163 
164  _models[filename] = node;
165  }
166 
167  return node;
168 }
169 
170 /**
171  * The nonstatic implementation of add_model().
172  */
173 void ModelPool::
174 ns_add_model(const Filename &filename, ModelRoot *model) {
175  LightMutexHolder holder(_lock);
176  if (pgraph_cat.is_debug()) {
177  pgraph_cat.debug()
178  << "ModelPool storing " << model << " for " << filename << "\n";
179  }
180  // We blow away whatever model was there previously, if any.
181  _models[filename] = model;
182 }
183 
184 /**
185  * The nonstatic implementation of release_model().
186  */
187 void ModelPool::
188 ns_release_model(const Filename &filename) {
189  LightMutexHolder holder(_lock);
190  Models::iterator ti;
191  ti = _models.find(filename);
192  if (ti != _models.end()) {
193  _models.erase(ti);
194  }
195 }
196 
197 /**
198  * The nonstatic implementation of add_model().
199  */
200 void ModelPool::
201 ns_add_model(ModelRoot *model) {
202  LightMutexHolder holder(_lock);
203  // We blow away whatever model was there previously, if any.
204  _models[model->get_fullpath()] = model;
205 }
206 
207 /**
208  * The nonstatic implementation of release_model().
209  */
210 void ModelPool::
211 ns_release_model(ModelRoot *model) {
212  LightMutexHolder holder(_lock);
213  Models::iterator ti;
214  ti = _models.find(model->get_fullpath());
215  if (ti != _models.end()) {
216  _models.erase(ti);
217  }
218 }
219 
220 /**
221  * The nonstatic implementation of release_all_models().
222  */
223 void ModelPool::
224 ns_release_all_models() {
225  LightMutexHolder holder(_lock);
226  _models.clear();
227 }
228 
229 /**
230  * The nonstatic implementation of garbage_collect().
231  */
232 int ModelPool::
233 ns_garbage_collect() {
234  LightMutexHolder holder(_lock);
235 
236  int num_released = 0;
237  Models new_set;
238 
239  Models::iterator ti;
240  for (ti = _models.begin(); ti != _models.end(); ++ti) {
241  ModelRoot *node = (*ti).second;
242  if (node == nullptr ||
243  node->get_model_ref_count() == 1) {
244  if (loader_cat.is_debug()) {
245  loader_cat.debug()
246  << "Releasing " << (*ti).first << "\n";
247  }
248  ++num_released;
249  } else {
250  new_set.insert(new_set.end(), *ti);
251  }
252  }
253 
254  _models.swap(new_set);
255  return num_released;
256 }
257 
258 /**
259  * The nonstatic implementation of list_contents().
260  */
261 void ModelPool::
262 ns_list_contents(std::ostream &out) const {
263  LightMutexHolder holder(_lock);
264 
265  out << "model pool contents:\n";
266 
267  Models::const_iterator ti;
268  int num_models = 0;
269  for (ti = _models.begin(); ti != _models.end(); ++ti) {
270  if ((*ti).second != nullptr) {
271  ++num_models;
272  out << (*ti).first << "\n"
273  << " (count = " << (*ti).second->get_model_ref_count()
274  << ")\n";
275  }
276  }
277 
278  out << "total number of models: " << num_models << " (plus "
279  << _models.size() - num_models << " entries for nonexistent files)\n";
280 }
281 
282 /**
283  * Initializes and/or returns the global pointer to the one ModelPool object
284  * in the system.
285  */
286 ModelPool *ModelPool::
287 get_ptr() {
288  if (_global_ptr == nullptr) {
289  _global_ptr = new ModelPool;
290  }
291  return _global_ptr;
292 }
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
ModelRoot::get_model_ref_count
get_model_ref_count
Returns the number of copies that exist of this particular ModelRoot node.
Definition: modelRoot.h:33
Loader
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
Definition: loader.h:42
modelPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
VirtualFileSystem::get_file
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
Definition: virtualFileSystem.cxx:516
ModelRoot::get_fullpath
get_fullpath
Returns the full pathname of the model represented by this node, as found on disk.
Definition: modelRoot.h:37
VirtualFileSystem::exists
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
Definition: virtualFileSystem.I:18
LoaderOptions
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
ModelPool::write
static void write(std::ostream &out)
Lists the contents of the model pool to the indicated output stream.
Definition: modelPool.cxx:28
ModelPool
This class unifies all references to the same filename, so that multiple attempts to load the same mo...
Definition: modelPool.h:42
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition: virtualFileSystem.cxx:742
virtualFileSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ModelRoot
A node of this type is created automatically at the root of each model file that is loaded.
Definition: modelRoot.h:27
VirtualFile
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
loader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Loader::get_global_ptr
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
Definition: loader.I:212
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39