rework loader vs. ModelPool; deprecate implicit filename extension; improve ModelPool.releaseModel()
This commit is contained in:
parent
8768f41974
commit
dfe5814829
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue