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;
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;
210 if (!filename.is_local()) {
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";
289 bool allow_ram_cache = requested_type->get_allow_ram_cache(options);
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());
311 if (cache->get_cache_models() && requested_type->get_allow_disk_cache(options)) {
314 record = cache->lookup(pathname,
"bam");
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);
357 if (result != (PandaNode *)NULL) {
360 record->set_data(result, result);
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();
394 PandaNode *node)
const {
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...
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.
const Filename & get_directory(int n) const
Returns the nth directory 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.
This class unifies all references to the same filename, so that multiple attempts to load the same mo...
virtual bool supports_load() const
Returns true if the file type can be used to load files, and load_file() is supported.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
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...
virtual bool supports_save() const
Returns true if the file type can be used to save files, and save_file() is supported.
bool has_data() const
Returns true if this cache record has an in-memory data object associated–that is, the object stored in the cache.
bool store(BamCacheRecord *record)
Flushes a cache entry to disk.
void set_timestamp(time_t timestamp)
Sets the timestamp of the file on disk that was read for this model.
A base class for all things which can have a name.
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...
int get_num_unique_values() const
Returns the number of unique values in 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.
int get_num_directories() const
Returns the number of directories on the search list.
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.
This class maintains the set of all known LoaderFileTypes in the universe.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
time_t get_source_timestamp() const
Returns the file timestamp of the original source file that generated this cache record, if available.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
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.
const string & get_value() const
Returns the variable's value.
string get_unique_value(int n) const
Returns the nth unique value of the variable.
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
A class object that manages a single asynchronous model load request.
TypeHandle is the identifier used to differentiate C++ class types.
static AsyncTaskManager * get_global_ptr()
Returns a pointer to the global AsyncTaskManager.
void write(ostream &out, int indent_level=0) const
Writes a list of supported file types to the indicated output stream, one per line.
static BamCache * get_global_ptr()
Returns a pointer to the global BamCache object, which is used automatically by the ModelPool and Tex...