rework loader vs. ModelPool; deprecate implicit filename extension; improve ModelPool.releaseModel()

This commit is contained in:
David Rose 2006-10-25 17:56:50 +00:00
parent 8768f41974
commit dfe5814829
14 changed files with 334 additions and 239 deletions

View File

@ -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,

View File

@ -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

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 &copy) :
ModelNode(copy),
_fullpath(copy._fullpath),
_reference(copy._reference)
{
}

View File

@ -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 &copy);
@ -54,6 +57,7 @@ public:
virtual PandaNode *make_copy() const;
private:
Filename _fullpath;
PT(ModelReference) _reference;
public: