16 #include "loaderFileType.h" 17 #include "loaderFileTypeRegistry.h" 18 #include "config_pgraph.h" 19 #include "modelPool.h" 20 #include "modelLoadRequest.h" 21 #include "modelSaveRequest.h" 22 #include "config_express.h" 23 #include "config_util.h" 24 #include "virtualFileSystem.h" 27 #include "string_utils.h" 29 #include "bamCacheRecord.h" 30 #include "sceneGraphReducer.h" 31 #include "renderState.h" 33 #include "configVariableInt.h" 34 #include "configVariableEnum.h" 36 bool Loader::_file_types_loaded =
false;
37 PT(
Loader) Loader::_global_ptr;
46 Loader(
const string &name) :
52 if (_task_manager->find_task_chain(_task_chain) == NULL) {
53 PT(
AsyncTaskChain) chain = _task_manager->make_task_chain(_task_chain);
56 (
"loader-num-threads", 1,
57 PRC_DESC(
"The number of threads that will be started by the Loader class " 58 "to load models asynchronously. These threads will only be " 59 "started if the asynchronous interface is used, and if threading " 60 "support is compiled into Panda. The default is one thread, " 61 "which allows models to be loaded one at a time in a single " 62 "asychronous thread. You can set this higher, particularly if " 63 "you have many CPU's available, to allow loading multiple models " 65 chain->set_num_threads(loader_num_threads);
68 (
"loader-thread-priority", TP_low,
69 PRC_DESC(
"The default thread priority to assign to the threads created " 70 "for asynchronous loading. The default is 'low'; you may " 71 "also specify 'normal', 'high', or 'urgent'."));
72 chain->set_thread_priority(loader_thread_priority);
85 filename, options,
this);
98 filename, options, node,
this);
108 load_bam_stream(istream &in) {
114 return bam_file.read_node();
123 output(ostream &out)
const {
124 out << get_type() <<
" " << get_name();
126 int num_tasks = _task_manager->make_task_chain(_task_chain)->get_num_tasks();
127 if (num_tasks != 0) {
128 out <<
" (" << num_tasks <<
" models pending)";
148 bool report_errors = (this_options.get_flags() & LoaderOptions::LF_report_errors) != 0;
150 string extension = this_filename.get_extension();
151 if (extension.empty()) {
154 this_filename = this_filename.get_fullpath() + default_model_extension.
get_value();
155 extension = this_filename.get_extension();
158 bool pz_file =
false;
160 if (extension ==
"pz") {
162 extension =
Filename(this_filename.get_basename_wo_extension()).get_extension();
166 if (extension.empty()) {
169 <<
"Cannot load " << this_filename
170 <<
" without filename extension. Loading of model filenames with an " 171 "implicit extension is deprecated in Panda3D. Please " 172 "correct the filename reference. If necessary, you may put the " 173 "line \"default-model-extension .bam\" or \"default-model-extension .egg\" " 174 "in your Config.prc to globally assume a particular model " 175 "filename extension.\n";
186 <<
"Extension of file " << this_filename
187 <<
" is unrecognized; cannot load.\n";
188 loader_cat.error(
false)
189 <<
"Currently known scene file types are:\n";
190 reg->
write(loader_cat.error(
false), 2);
196 << requested_type->get_name() <<
" file type (." 197 << extension <<
") does not support loading.\n";
203 << requested_type->get_name() <<
" file type (." 204 << extension <<
") does not support in-line compression.\n";
209 bool search = (this_options.get_flags() & LoaderOptions::LF_search) != 0;
217 this_options.set_flags(this_options.get_flags() & ~
LoaderOptions::LF_search);
225 for (
int i = 0; i < num_dirs; ++i) {
227 PT(
PandaNode) result = try_load_file(pathname, this_options,
235 bool any_exist =
false;
236 for (
int i = 0; i < num_dirs; ++i) {
238 if (vfs->
exists(pathname)) {
246 <<
"Couldn't load file " << this_filename
247 <<
": all matching files on model path invalid " 248 <<
"(the model path is currently: \"" << get_model_path() <<
"\")\n";
251 <<
"Couldn't load file " << this_filename
252 <<
": not found on model path " 253 <<
"(currently: \"" << get_model_path() <<
"\")\n";
260 PT(
PandaNode) result = try_load_file(this_filename, this_options, requested_type);
265 if (vfs->
exists(this_filename)) {
267 <<
"Couldn't load file " << this_filename <<
": invalid.\n";
270 <<
"Couldn't load file " << this_filename <<
": does not exist.\n";
291 if (allow_ram_cache) {
296 if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
297 if (loader_cat.is_debug()) {
299 <<
"Model " << pathname <<
" found in ModelPool.\n";
302 node = node->copy_subgraph();
308 bool report_errors = ((options.get_flags() & LoaderOptions::LF_report_errors) != 0 || loader_cat.is_debug());
314 record = cache->lookup(pathname,
"bam");
316 if (record->has_data()) {
319 <<
"Model " << pathname <<
" found in disk cache.\n";
325 sgr.
premunge(result, RenderState::make_empty());
328 if (result->is_of_type(ModelRoot::get_class_type())) {
333 if (allow_ram_cache) {
338 if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
339 return model_root->copy_subgraph();
347 if (loader_cat.is_debug()) {
349 <<
"Model " << pathname <<
" not found in cache.\n";
353 bool cache_only = (options.get_flags() & LoaderOptions::LF_cache_only) != 0;
356 PT(
PandaNode) result = requested_type->load_file(pathname, options, record);
361 cache->
store(record);
366 sgr.
premunge(result, RenderState::make_empty());
369 if (allow_ram_cache && result->is_of_type(ModelRoot::get_class_type())) {
374 if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
375 result = result->copy_subgraph();
398 bool report_errors = (this_options.get_flags() & LoaderOptions::LF_report_errors) != 0;
400 string extension = this_filename.get_extension();
401 if (extension.empty()) {
404 this_filename = this_filename.get_fullpath() + default_model_extension.
get_value();
405 extension = this_filename.get_extension();
408 bool pz_file =
false;
410 if (extension ==
"pz") {
412 extension =
Filename(this_filename.get_basename_wo_extension()).get_extension();
416 if (extension.empty()) {
419 <<
"Cannot save " << this_filename
420 <<
" without filename extension.\n";
432 <<
"Extension of file " << this_filename
433 <<
" is unrecognized; cannot save.\n";
434 loader_cat.error(
false)
435 <<
"Currently known scene file types are:\n";
436 reg->
write(loader_cat.error(
false), 2);
443 << requested_type->get_name() <<
" file type (." 444 << extension <<
") does not support saving.\n";
451 << requested_type->get_name() <<
" file type (." 452 << extension <<
") does not support in-line compression.\n";
459 bool result = try_save_file(this_filename, this_options, node, requested_type);
463 <<
"Couldn't save file " << this_filename <<
".\n";
479 bool report_errors = ((options.get_flags() & LoaderOptions::LF_report_errors) != 0 || loader_cat.is_debug());
481 bool result = requested_type->save_file(pathname, options, node);
495 if (!_file_types_loaded) {
498 for (
int i = 0; i < num_unique_values; i++) {
502 extract_words(param, words);
504 if (words.size() == 1) {
506 string name = words[0];
507 Filename dlname = Filename::dso_filename(
"lib" + name +
".so");
509 <<
"loading file type module: " << name << endl;
510 void *tmp = load_dso(get_plugin_path().get_value(), dlname);
511 if (tmp == (
void *)NULL) {
514 <<
": " << load_dso_error() << endl;
515 }
else if (loader_cat.is_debug()) {
517 <<
"done loading file type module: " << name << endl;
520 }
else if (words.size() > 1) {
525 size_t num_extensions = words.size() - 1;
526 string library_name = words[num_extensions];
528 for (
size_t i = 0; i < num_extensions; i++) {
529 string extension = words[i];
530 if (extension[0] ==
'.') {
531 extension = extension.substr(1);
539 _file_types_loaded =
true;
551 nassertv(_global_ptr == (
Loader *)NULL);
553 _global_ptr =
new Loader(
"loader");
The principle public interface to reading and writing Bam disk files.
A node of this type is created automatically at the root of each model file that is loaded...
void set_data(TypedWritable *ptr, ReferenceCount *ref_ptr)
Stores a new data object on the record.
string get_basename() const
Returns the basename part of the filename.
This is similar to a ConfigVariableList, but it returns its list as a DSearchPath, as a list of directories.
A basic node of the scene graph or data graph.
static void add_model(const Filename &filename, ModelRoot *model)
Adds the indicated already-loaded model to the pool.
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
A class object that manages a single asynchronous model save request.
TypedWritable * get_data() const
Returns a pointer to the data stored in the record, or NULL if there is no data.
int get_num_directories() const
Returns the number of directories on the search list.
Specifies parameters that may be passed to the loader.
This class maintains a cache of Bam and/or Txo objects generated from model files and texture images ...
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
static LoaderFileTypeRegistry * get_global_ptr()
Returns a pointer to the global LoaderFileTypeRegistry object.
void set_fullpath(const Filename &fullpath)
Sets the full pathname of the model represented by this node, as found on disk.
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
void write(ostream &out, int indent_level=0) const
Writes a list of supported file types to the indicated output stream, one per line.
virtual bool get_allow_disk_cache(const LoaderOptions &options) const
Returns true if the loader flags allow retrieving the model from the on-disk bam cache (if it is enab...
const string & get_value() const
Returns the variable's value.
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
virtual bool get_allow_ram_cache(const LoaderOptions &options) const
Returns true if the loader flags allow retrieving the model from the in-memory ModelPool cache...
void set_timestamp(time_t timestamp)
Sets the timestamp of the file on disk that was read for this model.
const Filename & get_directory(int n) const
Returns the nth directory on the search list.
A base class for all things which can have a name.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
void register_deferred_type(const string &extension, const string &library)
Records a type associated with a particular extension to be loaded in the future. ...
The name of a file, such as a texture file or an Egg file.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
virtual bool supports_load() const
Returns true if the file type can be used to load files, and load_file() is supported.
string get_unique_value(int n) const
Returns the nth unique value of the variable.
LoaderFileType * get_type_from_extension(const string &extension)
Determines the type of the file based on the indicated extension (without a leading dot)...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
void premunge(PandaNode *root, const RenderState *initial_state)
Walks the scene graph rooted at this node and below, and uses the indicated GSG to premunge every Geo...
The AsyncTaskChain is a subset of the AsyncTaskManager.
This class specializes ConfigVariable as an enumerated type.
bool get_cache_models() const
Returns whether model files (e.g.
This class maintains the set of all known LoaderFileTypes in the universe.
bool is_local() const
Returns true if the filename is local, e.g.
virtual bool supports_save() const
Returns true if the file type can be used to save files, and save_file() is supported.
This class represents a concrete task performed by an AsyncManager.
This is the base class for a family of scene-graph file types that the Loader supports.
This is a convenience class to specialize ConfigVariable as an integer type.
int get_num_unique_values() const
Returns the number of unique values in the variable.
A class object that manages a single asynchronous model load request.
TypeHandle is the identifier used to differentiate C++ class types.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
static AsyncTaskManager * get_global_ptr()
Returns a pointer to the global AsyncTaskManager.
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...
static ModelRoot * get_model(const Filename &filename, bool verify)
Returns the model that has already been previously loaded, or NULL otherwise.