From dfe58148297f32497ab9e701c7dd2ad7c57ff6e0 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 25 Oct 2006 17:56:50 +0000 Subject: [PATCH] rework loader vs. ModelPool; deprecate implicit filename extension; improve ModelPool.releaseModel() --- direct/src/showbase/Loader.py | 34 ++- panda/src/pgraph/config_pgraph.cxx | 18 +- panda/src/pgraph/config_pgraph.h | 3 +- panda/src/pgraph/loader.cxx | 311 ++++++++++++---------------- panda/src/pgraph/loader.h | 3 - panda/src/pgraph/loaderFileType.cxx | 30 +++ panda/src/pgraph/loaderFileType.h | 6 + panda/src/pgraph/loaderOptions.I | 25 --- panda/src/pgraph/loaderOptions.h | 5 +- panda/src/pgraph/modelPool.I | 38 ++++ panda/src/pgraph/modelPool.cxx | 31 ++- panda/src/pgraph/modelPool.h | 30 ++- panda/src/pgraph/modelRoot.I | 33 +++ panda/src/pgraph/modelRoot.h | 6 +- 14 files changed, 334 insertions(+), 239 deletions(-) diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 42c71823b2..94ca4b2c3d 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -198,12 +198,38 @@ class Loader(DirectObject): return model - def unloadModel(self, modelPath): + def unloadModel(self, model): """ - modelPath is a string. + model is the return value of loadModel(). For backward + compatibility, it may also be the filename that was passed to + loadModel(), though this requires a disk search. """ - assert Loader.notify.debug("Unloading model: %s" % (modelPath)) - ModelPool.releaseModel(modelPath) + if isinstance(model, NodePath): + # Maybe we were given a NodePath + modelNode = model.node() + + elif isinstance(model, ModelNode): + # Maybe we were given a node + modelNode = model + + elif isinstance(model, types.StringTypes) or \ + isinstance(model, Filename): + # If we were given a filename, we have to ask the loader + # to resolve it for us. + options = LoaderOptions(LoaderOptions.LFSearch | LoaderOptions.LFNoDiskCache | LoaderOptions.LFCacheOnly) + modelNode = self.loader.loadSync(Filename(model), options) + if modelNode == None: + # Model not found. + assert Loader.notify.debug("Unloading model not loaded: %s" % (model)) + return + + assert Loader.notify.debug("%s resolves to %s" % (model, modelNode.getFullpath())) + + else: + raise 'Invalid parameter to unloadModel: %s' % (model) + + assert Loader.notify.debug("Unloading model: %s" % (modelNode.getFullpath())) + ModelPool.releaseModel(modelNode) # font loading funcs def loadFont(self, modelPath, diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 2c9a2e0765..670719244b 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -259,15 +259,6 @@ ConfigVariableBool m_dual_flash ("m-dual-flash", false, PRC_DESC("Set this true to flash any objects that use M_dual, for debugging.")); - -ConfigVariableBool asynchronous_loads -("asynchronous-loads", false, - PRC_DESC("Set this true to support actual asynchronous loads via the " - "request_load()/fetch_load() interface to Loader. Set it false to " - "map these to blocking, synchronous loads instead. Currently, the " - "rest of Panda isn't quite ready for asynchronous loads, so leave " - "this false for now.")); - ConfigVariableList load_file_type ("load-file-type", PRC_DESC("List the model loader modules that Panda will automatically " @@ -275,6 +266,15 @@ ConfigVariableList load_file_type "either the name of a module, or a space-separate list of filename " "extensions, followed by the name of the module.")); +ConfigVariableString default_model_extension +("default-model-extension", "", + PRC_DESC("This specifies the filename extension (with leading dot) that " + "should be assumed if an attempt is made to load a filename that " + "has no extension. This is primarily designed to support legacy " + "code that used the now-deprecated implicit-extension feature of " + "Panda's loader; new code should probably give the correct name " + "for each model file they intend to load.")); + //////////////////////////////////////////////////////////////////// // Function: init_libpgraph // Description: Initializes the library. This must be called at diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index 659daa2872..8b986fae72 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -61,9 +61,8 @@ extern ConfigVariableBool m_dual_opaque; extern ConfigVariableBool m_dual_transparent; extern ConfigVariableBool m_dual_flash; -extern ConfigVariableBool asynchronous_loads; - extern ConfigVariableList load_file_type; +extern ConfigVariableString default_model_extension; extern EXPCL_PANDA void init_libpgraph(); diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 5439f95aba..80eb0fa6bd 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -60,108 +60,6 @@ Loader(const string &name, int num_threads) : } } -//////////////////////////////////////////////////////////////////// -// Function: Loader::find_all_files -// Access: Published -// Description: Searches along the given search path for the given -// file name, and fills up the results list with all -// possible matches and their associated types, in -// order. -//////////////////////////////////////////////////////////////////// -int Loader:: -find_all_files(const Filename &filename, const DSearchPath &search_path, - Loader::Results &results) const { - if (!_file_types_loaded) { - load_file_types(); - } - string extension = filename.get_extension(); - string extra_ext; - bool pz_file = false; - -#ifdef HAVE_ZLIB - if (extension == "pz") { - // The extension ".pz" is special. This is an explicitly-named - // compressed file. We'll decompress it on the fly, if possible. - // (This relies on the auto_unwrap parameter to vfs->read_file(), - // which is different from the implicitly-named compressed file - // action that you might get if vfs-implicit-pz is enabled.) - extra_ext = extension; - extension = Filename(filename.get_basename_wo_extension()).get_extension(); - pz_file = true; - } -#endif // HAVE_ZLIB - - int num_added = 0; - - if (!extension.empty()) { - // If the extension is not empty, it specifies a single file type. - LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); - LoaderFileType *requested_type = - reg->get_type_from_extension(extension); - - if (requested_type != (LoaderFileType *)NULL && - (!pz_file || requested_type->supports_compressed())) { - if (!filename.is_local()) { - // Global filename, take it as it is. - results.add_file(filename, requested_type); - num_added++; - - } else { - // Local filename, search along the path. - DSearchPath::Results files; - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - num_added = vfs->find_all_files(filename, search_path, files); - - for (int i = 0; i < num_added; ++i) { - results.add_file(files.get_file(i), requested_type); - } - } - } - } else { - // If the extension *is* empty, we have to search for all possible - // file types. - LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); - int num_types = reg->get_num_types(); - - if (!filename.is_local()) { - // Global filename, take it as it is. - for (int t = 0; t < num_types; ++t) { - LoaderFileType *type = reg->get_type(t); - Filename file(filename); - file.set_extension(type->get_extension()); - file = file.get_fullpath() + extra_ext; - - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - if (vfs->exists(file)) { - results.add_file(file, type); - ++num_added; - } - } - } else { - // Local filename, look it up on the model path. - int num_dirs = search_path.get_num_directories(); - for (int i = 0; i < num_dirs; ++i) { - const Filename &directory = search_path.get_directory(i); - - for (int t = 0; t < num_types; ++t) { - LoaderFileType *type = reg->get_type(t); - Filename file(directory, filename); - file.set_extension(type->get_extension()); - file = file.get_fullpath() + extra_ext; - - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - if (vfs->exists(file)) { - results.add_file(file, type); - ++num_added; - } - } - } - } - } - - return num_added; -} - //////////////////////////////////////////////////////////////////// // Function: Loader::output // Access: Published, Virtual @@ -189,113 +87,164 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// PT(PandaNode) Loader:: load_file(const Filename &filename, const LoaderOptions &options) const { - if (options.get_allow_ram_cache()) { - // If we're allowing a RAM cache (and we don't have any other - // funny options), use the ModelPool to load the file. - PT(PandaNode) node = ModelPool::load_model(filename, options); - if (node != (PandaNode *)NULL) { - // But return a deep copy of the shared model. - node = node->copy_subgraph(); - } - return node; + Filename this_filename(filename); + LoaderOptions this_options(options); + + bool report_errors = (this_options.get_flags() & LoaderOptions::LF_report_errors) != 0; + + string extension = this_filename.get_extension(); + if (extension.empty()) { + // If the filename has no filename extension, append the default + // extension specified in the Config file. + this_filename = this_filename.get_fullpath() + default_model_extension.get_value(); + extension = this_filename.get_extension(); } - Results results; - int num_files; - - bool search = (options.get_flags() & LoaderOptions::LF_search) != 0; - - if (search) { - // Look for the file along the model path. - num_files = find_all_files(filename, get_model_path(), results); - } else { - // Look for the file only where it is. - num_files = find_all_files(filename, DSearchPath(Filename(".")), results); - } - - if (num_files == 0) { - // Couldn't find the file. Either it doesn't exist, or it's an - // unknown file type. Report a useful message either way. - string extension = filename.get_extension(); - bool pz_file = false; + bool pz_file = false; #ifdef HAVE_ZLIB - if (extension == "pz") { - pz_file = true; - extension = Filename(filename.get_basename_wo_extension()).get_extension(); - } + if (extension == "pz") { + pz_file = true; + extension = Filename(this_filename.get_basename_wo_extension()).get_extension(); + } #endif // HAVE_ZLIB - if (!extension.empty()) { - LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); - LoaderFileType *requested_type = - reg->get_type_from_extension(extension); - if (requested_type == (LoaderFileType *)NULL) { - loader_cat.error() - << "Extension of file " << filename - << " is unrecognized; cannot load.\n"; - loader_cat.error(false) - << "Currently known scene file types are:\n"; - reg->write(loader_cat.error(false), 2); - return NULL; - } else if (pz_file && !requested_type->supports_compressed()) { - loader_cat.error() - << requested_type->get_name() << " file type (." - << extension << ") does not support in-line compression.\n"; - return NULL; - } - } - if (search) { + if (extension.empty()) { + if (report_errors) { loader_cat.error() - << "Couldn't load file " << filename << ": not found on model path " - << "(which is currently: \"" << get_model_path() << "\")\n"; - } else { - loader_cat.error() - << "Couldn't load file ./" << filename << ": does not exist.\n"; + << "Cannot load " << this_filename + << " without filename extension. Loading of model filenames with an " + "implicit extension is deprecated in Panda3D. Please " + "correct the filename reference. If necessary, you may put the " + "line \"default-model-extension .bam\" or \"default-model-extension .egg\" " + "in your Config.prc to globally assume a particular model " + "filename extension.\n"; } return NULL; } + LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); + LoaderFileType *requested_type = + reg->get_type_from_extension(extension); + if (requested_type == (LoaderFileType *)NULL) { + if (report_errors) { + loader_cat.error() + << "Extension of file " << this_filename + << " is unrecognized; cannot load.\n"; + loader_cat.error(false) + << "Currently known scene file types are:\n"; + reg->write(loader_cat.error(false), 2); + } + return NULL; + } else if (pz_file && !requested_type->supports_compressed()) { + if (report_errors) { + loader_cat.error() + << requested_type->get_name() << " file type (." + << extension << ") does not support in-line compression.\n"; + } + return NULL; + } + + DSearchPath::Results results; + bool search = (this_options.get_flags() & LoaderOptions::LF_search) != 0; + if (!filename.is_local()) { + // If we have a global filename, we don't search the model path. + search = false; + } + + bool cache_only = (this_options.get_flags() & LoaderOptions::LF_cache_only) != 0; + + VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); + + if (search) { + // Look for the file along the model path. + vfs->find_all_files(this_filename, get_model_path(), results); + + if (results.get_num_files() == 0) { + if (report_errors) { + loader_cat.error() + << "Couldn't load file " << this_filename << ": not found on model path " + << "(which is currently: \"" << get_model_path() << "\")\n"; + } + return NULL; + } + + } else { + // Look for the file only where it is. + if (vfs->exists(this_filename)) { + results.add_file(this_filename); + + } else { + if (report_errors) { + loader_cat.error() + << "Couldn't load file " << this_filename << ": does not exist.\n"; + } + return NULL; + } + } + + // Now that we've searched for the file, don't try to search again. + this_options.set_flags(this_options.get_flags() & ~LoaderOptions::LF_search); + BamCache *cache = BamCache::get_global_ptr(); + int num_files = results.get_num_files(); for (int i = 0; i < num_files; ++i) { const Filename &path = results.get_file(i); - PT(BamCacheRecord) record; + if (requested_type->get_allow_ram_cache(this_options)) { + // If we're allowing a RAM cache, use the ModelPool to load the + // file. + if (!cache_only || ModelPool::has_model(path)) { + PT(PandaNode) node = ModelPool::load_model(path, this_options); + if (node != (PandaNode *)NULL && + (this_options.get_flags() & LoaderOptions::LF_allow_instance) == 0) { + // But return a deep copy of the shared model. + node = node->copy_subgraph(); + } + return node; + } + } - if (cache->get_active() && options.get_allow_disk_cache()) { - // See if the texture can be found in the on-disk cache, if it is + PT(BamCacheRecord) record; + if (cache->get_active() && requested_type->get_allow_disk_cache(this_options)) { + // See if the model can be found in the on-disk cache, if it is // active. record = cache->lookup(path, "bam"); if (record != (BamCacheRecord *)NULL) { if (record->has_data()) { - loader_cat.info() - << "Model " << path << " found in disk cache.\n"; + if (report_errors) { + loader_cat.info() + << "Model " << path << " found in disk cache.\n"; + } return DCAST(PandaNode, record->extract_data()); } } } - LoaderFileType *type = results.get_file_type(i); - PT(PandaNode) result = type->load_file(path, options, record); - if (result != (PandaNode *)NULL){ - if (record != (BamCacheRecord *)NULL) { - record->set_data(result, false); - cache->store(record); + if (!cache_only) { + PT(PandaNode) result = requested_type->load_file(path, this_options, record); + if (result != (PandaNode *)NULL){ + if (record != (BamCacheRecord *)NULL) { + record->set_data(result, false); + cache->store(record); + } + + return result; } - - return result; } } - // None of the matching files could be loaded. Oh well. - if (search) { - loader_cat.error() - << "Couldn't load file " << filename - << ": all matching files on model path invalid " - << "(the model path is currently: \"" << get_model_path() << "\")\n"; - } else { - loader_cat.error() - << "Couldn't load file " << filename - << ": invalid.\n"; + if (report_errors) { + // None of the matching files could be loaded. Oh well. + if (num_files > 1) { + loader_cat.error() + << "Couldn't load file " << this_filename + << ": all matching files on model path invalid " + << "(the model path is currently: \"" << get_model_path() << "\")\n"; + } else { + loader_cat.error() + << "Couldn't load file " << this_filename + << ": invalid.\n"; + } } return NULL; } diff --git a/panda/src/pgraph/loader.h b/panda/src/pgraph/loader.h index e537f2b4f9..baf6d00248 100644 --- a/panda/src/pgraph/loader.h +++ b/panda/src/pgraph/loader.h @@ -79,9 +79,6 @@ PUBLISHED: Loader(const string &name = "loader", int num_threads = -1); - int find_all_files(const Filename &filename, const DSearchPath &search_path, - Results &results) const; - INLINE PT(PandaNode) load_sync(const Filename &filename, const LoaderOptions &options = LoaderOptions()) const; diff --git a/panda/src/pgraph/loaderFileType.cxx b/panda/src/pgraph/loaderFileType.cxx index 7f8026d3d8..7b3ed79a96 100644 --- a/panda/src/pgraph/loaderFileType.cxx +++ b/panda/src/pgraph/loaderFileType.cxx @@ -28,6 +28,12 @@ TypeHandle LoaderFileType::_type_handle; //////////////////////////////////////////////////////////////////// LoaderFileType:: LoaderFileType() { + // Derived LoaderFileType classes that return a different result + // based on the setting of certain LoaderOptions flags (like + // LF_convert_anim) should set those bits in the following bitmask, + // so that we will not inadvertently cache a model without + // respecting these flags. + _no_cache_flags = 0; } //////////////////////////////////////////////////////////////////// @@ -63,6 +69,30 @@ supports_compressed() const { return false; } +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileType::get_allow_disk_cache +// Access: Published, Virtual +// Description: Returns true if the loader flags allow retrieving the +// model from the on-disk bam cache (if it is enabled), +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool LoaderFileType:: +get_allow_disk_cache(const LoaderOptions &options) const { + return (options.get_flags() & (LoaderOptions::LF_no_disk_cache | _no_cache_flags)) == 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileType::get_allow_ram_cache +// Access: Published +// Description: Returns true if the loader flags allow retrieving the +// model from the in-memory ModelPool cache, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool LoaderFileType:: +get_allow_ram_cache(const LoaderOptions &options) const { + return (options.get_flags() & (LoaderOptions::LF_no_ram_cache | _no_cache_flags)) == 0; +} + //////////////////////////////////////////////////////////////////// // Function: LoaderFileType::load_file // Access: Public, Virtual diff --git a/panda/src/pgraph/loaderFileType.h b/panda/src/pgraph/loaderFileType.h index c61554d667..a5bc12ebcf 100644 --- a/panda/src/pgraph/loaderFileType.h +++ b/panda/src/pgraph/loaderFileType.h @@ -50,10 +50,16 @@ PUBLISHED: virtual string get_additional_extensions() const; virtual bool supports_compressed() const; + virtual bool get_allow_disk_cache(const LoaderOptions &options) const; + virtual bool get_allow_ram_cache(const LoaderOptions &options) const; + public: virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options, BamCacheRecord *record) const; +protected: + int _no_cache_flags; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/pgraph/loaderOptions.I b/panda/src/pgraph/loaderOptions.I index 1fc1dbacab..74cb954182 100644 --- a/panda/src/pgraph/loaderOptions.I +++ b/panda/src/pgraph/loaderOptions.I @@ -68,28 +68,3 @@ INLINE int LoaderOptions:: get_flags() const { return _flags; } - -//////////////////////////////////////////////////////////////////// -// Function: LoaderOptions::get_allow_disk_cache -// Access: Published -// Description: Returns true if the loader flags allow retrieving the -// model from the on-disk bam cache (if it is enabled), -// false otherwise. -//////////////////////////////////////////////////////////////////// -INLINE bool LoaderOptions:: -get_allow_disk_cache() const { - return (_flags & LF_no_disk_cache) == 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: LoaderOptions::get_allow_ram_cache -// Access: Published -// Description: Returns true if the loader flags allow retrieving the -// model from the in-memory ModelPool cache, false -// otherwise. -//////////////////////////////////////////////////////////////////// -INLINE bool LoaderOptions:: -get_allow_ram_cache() const { - return ((_flags & (LF_no_ram_cache | LF_convert_anim)) == 0 && - (_flags & LF_search) != 0); -} diff --git a/panda/src/pgraph/loaderOptions.h b/panda/src/pgraph/loaderOptions.h index f08d803446..3507baa018 100644 --- a/panda/src/pgraph/loaderOptions.h +++ b/panda/src/pgraph/loaderOptions.h @@ -39,6 +39,8 @@ PUBLISHED: LF_no_disk_cache = 0x0010, // disallow BamCache LF_no_ram_cache = 0x0020, // disallow ModelPool LF_no_cache = 0x0030, // no_disk + no_ram + LF_cache_only = 0x0040, // fail if not in cache + LF_allow_instance = 0x0080, // returned pointer might be shared }; INLINE LoaderOptions(int flags = LF_search | LF_report_errors); @@ -48,9 +50,6 @@ PUBLISHED: INLINE void set_flags(int flags); INLINE int get_flags() const; - INLINE bool get_allow_disk_cache() const; - INLINE bool get_allow_ram_cache() const; - void output(ostream &out) const; private: diff --git a/panda/src/pgraph/modelPool.I b/panda/src/pgraph/modelPool.I index 503f1eec87..9037576808 100644 --- a/panda/src/pgraph/modelPool.I +++ b/panda/src/pgraph/modelPool.I @@ -64,6 +64,10 @@ load_model(const string &filename, const LoaderOptions &options) { // pool. The model will always replace any // previously-loaded model in the pool that had the // same filename. +// +// This two-parameter version of this method is +// deprecated; use the one-parameter add_model(model) +// instead. //////////////////////////////////////////////////////////////////// INLINE void ModelPool:: add_model(const string &filename, ModelRoot *model) { @@ -78,12 +82,46 @@ add_model(const string &filename, ModelRoot *model) { // may then be freed. If this function is never called, // a reference count will be maintained on every model // every loaded, and models will never be freed. +// +// This version of this method is deprecated; use +// release_model(model) instead. //////////////////////////////////////////////////////////////////// INLINE void ModelPool:: release_model(const string &filename) { get_ptr()->ns_release_model(filename); } +//////////////////////////////////////////////////////////////////// +// Function: ModelPool::add_model +// Access: Public, Static +// Description: Adds the indicated already-loaded model to the +// pool. The model will always replace any +// previously-loaded model in the pool that had the +// same filename. +//////////////////////////////////////////////////////////////////// +INLINE void ModelPool:: +add_model(ModelRoot *model) { + get_ptr()->ns_add_model(model); +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelPool::release_model +// Access: Public, Static +// Description: Removes the indicated model from the pool, +// indicating it will never be loaded again; the model +// may then be freed. If this function is never called, +// a reference count will be maintained on every model +// every loaded, and models will never be freed. +// +// The model's get_fullpath() value should not have been +// changed during its lifetime, or this function may +// fail to locate it in the pool. +//////////////////////////////////////////////////////////////////// +INLINE void ModelPool:: +release_model(ModelRoot *model) { + get_ptr()->ns_release_model(model); +} + //////////////////////////////////////////////////////////////////// // Function: ModelPool::release_all_models // Access: Public, Static diff --git a/panda/src/pgraph/modelPool.cxx b/panda/src/pgraph/modelPool.cxx index 27589376b4..fd40e952a2 100644 --- a/panda/src/pgraph/modelPool.cxx +++ b/panda/src/pgraph/modelPool.cxx @@ -76,7 +76,8 @@ ns_load_model(const string &filename, const LoaderOptions &options) { loader_cat.info() << "Loading model " << filename << "\n"; LoaderOptions new_options(options); - new_options.set_flags(new_options.get_flags() | LoaderOptions::LF_no_ram_cache); + new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) & + ~LoaderOptions::LF_search); PT(PandaNode) panda_node = model_loader.load_sync(filename, new_options); if (panda_node.is_null()) { @@ -93,6 +94,7 @@ ns_load_model(const string &filename, const LoaderOptions &options) { node = new ModelRoot(filename); node->add_child(panda_node); } + node->set_fullpath(filename); { MutexHolder holder(_lock); @@ -139,6 +141,33 @@ ns_release_model(const string &filename) { } } +//////////////////////////////////////////////////////////////////// +// Function: ModelPool::ns_add_model +// Access: Private +// Description: The nonstatic implementation of add_model(). +//////////////////////////////////////////////////////////////////// +void ModelPool:: +ns_add_model(ModelRoot *model) { + MutexHolder holder(_lock); + // We blow away whatever model was there previously, if any. + _models[model->get_fullpath()] = model; +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelPool::ns_release_model +// Access: Private +// Description: The nonstatic implementation of release_model(). +//////////////////////////////////////////////////////////////////// +void ModelPool:: +ns_release_model(ModelRoot *model) { + MutexHolder holder(_lock); + Models::iterator ti; + ti = _models.find(model->get_fullpath()); + if (ti != _models.end()) { + _models.erase(ti); + } +} + //////////////////////////////////////////////////////////////////// // Function: ModelPool::ns_release_all_models // Access: Private diff --git a/panda/src/pgraph/modelPool.h b/panda/src/pgraph/modelPool.h index 6fe4c2f34b..2655ca5aff 100644 --- a/panda/src/pgraph/modelPool.h +++ b/panda/src/pgraph/modelPool.h @@ -30,22 +30,24 @@ //////////////////////////////////////////////////////////////////// // Class : ModelPool -// Description : This is the preferred interface for loading models. -// It unifies all references to the same filename, so -// that multiple attempts to load the same model will -// return the same pointer. Note that the default -// behavior is thus to make instances: use with caution. -// Use the copy_subgraph() method on Node (or use -// NodePath::copy_to) to make modifiable copies of the -// node. +// Description : This class unifies all references to the same +// filename, so that multiple attempts to load the same +// model will return the same pointer. Note that the +// default behavior is thus to make instances: use with +// caution. Use the copy_subgraph() method on Node (or +// use NodePath::copy_to) to make modifiable copies of +// the node. // // Unlike TexturePool, this class does not automatically // resolve the model filenames before loading, so a // relative path and an absolute path to the same model // will appear to be different filenames. // -// This does not presently support asynchronous loading, -// although it wouldn't be *too* difficult to add. +// However, see the Loader class, which is now the +// preferred interface for loading models. The Loader +// class can resolve filenames, supports threaded +// loading, and can automatically consult the ModelPool, +// according to the supplied LoaderOptions. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA ModelPool { PUBLISHED: @@ -56,6 +58,10 @@ PUBLISHED: INLINE static void add_model(const string &filename, ModelRoot *model); INLINE static void release_model(const string &filename); + + INLINE static void add_model(ModelRoot *model); + INLINE static void release_model(ModelRoot *model); + INLINE static void release_all_models(); INLINE static int garbage_collect(); @@ -71,6 +77,10 @@ private: const LoaderOptions &options); void ns_add_model(const string &filename, ModelRoot *model); void ns_release_model(const string &filename); + + void ns_add_model(ModelRoot *model); + void ns_release_model(ModelRoot *model); + void ns_release_all_models(); int ns_garbage_collect(); void ns_list_contents(ostream &out) const; diff --git a/panda/src/pgraph/modelRoot.I b/panda/src/pgraph/modelRoot.I index 374e06b5af..c68fb738f1 100644 --- a/panda/src/pgraph/modelRoot.I +++ b/panda/src/pgraph/modelRoot.I @@ -25,6 +25,7 @@ INLINE ModelRoot:: ModelRoot(const string &name) : ModelNode(name), + _fullpath(name), _reference(new ModelRoot::ModelReference) { } @@ -45,6 +46,37 @@ get_model_ref_count() const { return _reference->get_ref_count(); } +//////////////////////////////////////////////////////////////////// +// Function: ModelRoot::get_fullpath +// Access: Published +// Description: Returns the full pathname of the model represented by +// this node, as found on disk. This is mainly useful +// for reference purposes, but is also used to index the +// ModelRoot into the ModelPool. +//////////////////////////////////////////////////////////////////// +INLINE const Filename &ModelRoot:: +get_fullpath() const { + return _fullpath; +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelRoot::set_fullpath +// Access: Published +// Description: Sets the full pathname of the model represented by +// this node, as found on disk. This is mainly useful +// for reference purposes, but is also used to index the +// ModelRoot into the ModelPool. +// +// This is normally set automatically when a model is +// loaded, and should not be set directly by the user. +// If you change this on a loaded model, then +// ModelPool::release_model() may fail. +//////////////////////////////////////////////////////////////////// +INLINE void ModelRoot:: +set_fullpath(const Filename &fullpath) { + _fullpath = fullpath; +} + //////////////////////////////////////////////////////////////////// // Function: ModelRoot::get_reference // Access: Published @@ -81,6 +113,7 @@ set_reference(ModelRoot::ModelReference *ref) { INLINE ModelRoot:: ModelRoot(const ModelRoot ©) : ModelNode(copy), + _fullpath(copy._fullpath), _reference(copy._reference) { } diff --git a/panda/src/pgraph/modelRoot.h b/panda/src/pgraph/modelRoot.h index c7159ce461..7377f62f4c 100644 --- a/panda/src/pgraph/modelRoot.h +++ b/panda/src/pgraph/modelRoot.h @@ -38,6 +38,9 @@ PUBLISHED: INLINE int get_model_ref_count() const; + INLINE const Filename &get_fullpath() const; + INLINE void set_fullpath(const Filename &fullpath); + // This class is used to unify references to the same model. class ModelReference : public ReferenceCount { PUBLISHED: @@ -45,7 +48,7 @@ PUBLISHED: }; INLINE ModelReference *get_reference() const; - INLINE void set_reference(ModelReference *ref); + void set_reference(ModelReference *ref); protected: INLINE ModelRoot(const ModelRoot ©); @@ -54,6 +57,7 @@ public: virtual PandaNode *make_copy() const; private: + Filename _fullpath; PT(ModelReference) _reference; public: