Panda3D
Loading...
Searching...
No Matches
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
21ModelPool *ModelPool::_global_ptr = nullptr;
22
23/**
24 * Lists the contents of the model pool to the indicated output stream. Helps
25 * with debugging.
26 */
28write(std::ostream &out) {
29 get_ptr()->ns_list_contents(out);
30}
31
32/**
33 * The nonstatic implementation of has_model().
34 */
35bool ModelPool::
36ns_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 */
51ModelRoot *ModelPool::
52ns_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 */
119ModelRoot *ModelPool::
120ns_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 */
173void ModelPool::
174ns_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 */
187void ModelPool::
188ns_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 */
200void ModelPool::
201ns_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 */
210void ModelPool::
211ns_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 */
223void ModelPool::
224ns_release_all_models() {
225 LightMutexHolder holder(_lock);
226 _models.clear();
227}
228
229/**
230 * The nonstatic implementation of garbage_collect().
231 */
232int ModelPool::
233ns_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 */
261void ModelPool::
262ns_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 */
286ModelPool *ModelPool::
287get_ptr() {
288 if (_global_ptr == nullptr) {
289 _global_ptr = new ModelPool;
290 }
291 return _global_ptr;
292}
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.
Specifies parameters that may be passed to the 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
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
Definition loader.I:212
This class unifies all references to the same filename, so that multiple attempts to load the same mo...
Definition modelPool.h:42
static void write(std::ostream &out)
Lists the contents of the model pool to the indicated output stream.
Definition modelPool.cxx:28
A node of this type is created automatically at the root of each model file that is loaded.
Definition modelRoot.h:27
get_fullpath
Returns the full pathname of the model represented by this node, as found on disk.
Definition modelRoot.h:37
get_model_ref_count
Returns the number of copies that exist of this particular ModelRoot node.
Definition modelRoot.h:33
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
A hierarchy of directories and files that appears to be one continuous file system,...
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists in the virtual file system hierarchy.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition virtualFile.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.