00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "loader.h"
00016 #include "loaderFileType.h"
00017 #include "loaderFileTypeRegistry.h"
00018 #include "config_pgraph.h"
00019 #include "modelPool.h"
00020 #include "modelLoadRequest.h"
00021 #include "config_express.h"
00022 #include "config_util.h"
00023 #include "virtualFileSystem.h"
00024 #include "filename.h"
00025 #include "load_dso.h"
00026 #include "string_utils.h"
00027 #include "bamCache.h"
00028 #include "bamCacheRecord.h"
00029 #include "sceneGraphReducer.h"
00030 #include "renderState.h"
00031 #include "bamFile.h"
00032 #include "configVariableInt.h"
00033 #include "configVariableEnum.h"
00034
00035 bool Loader::_file_types_loaded = false;
00036 PT(Loader) Loader::_global_ptr;
00037 TypeHandle Loader::_type_handle;
00038
00039
00040
00041
00042
00043
00044 Loader::
00045 Loader(const string &name) :
00046 Namable(name)
00047 {
00048 _task_manager = AsyncTaskManager::get_global_ptr();
00049 _task_chain = name;
00050
00051 if (_task_manager->find_task_chain(_task_chain) == NULL) {
00052 PT(AsyncTaskChain) chain = _task_manager->make_task_chain(_task_chain);
00053
00054 ConfigVariableInt loader_num_threads
00055 ("loader-num-threads", 1,
00056 PRC_DESC("The number of threads that will be started by the Loader class "
00057 "to load models asynchronously. These threads will only be "
00058 "started if the asynchronous interface is used, and if threading "
00059 "support is compiled into Panda. The default is one thread, "
00060 "which allows models to be loaded one at a time in a single "
00061 "asychronous thread. You can set this higher, particularly if "
00062 "you have many CPU's available, to allow loading multiple models "
00063 "simultaneously."));
00064 chain->set_num_threads(loader_num_threads);
00065
00066 ConfigVariableEnum<ThreadPriority> loader_thread_priority
00067 ("loader-thread-priority", TP_low,
00068 PRC_DESC("The default thread priority to assign to the threads created "
00069 "for asynchronous loading. The default is 'low'; you may "
00070 "also specify 'normal', 'high', or 'urgent'."));
00071 chain->set_thread_priority(loader_thread_priority);
00072 }
00073 }
00074
00075
00076
00077
00078
00079
00080
00081 PT(AsyncTask) Loader::
00082 make_async_request(const Filename &filename, const LoaderOptions &options) {
00083 return new ModelLoadRequest(string("model:")+filename.get_basename(),
00084 filename, options, this);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093 PT(PandaNode) Loader::
00094 load_bam_stream(istream &in) {
00095 BamFile bam_file;
00096 if (!bam_file.open_read(in)) {
00097 return NULL;
00098 }
00099
00100 return bam_file.read_node();
00101 }
00102
00103
00104
00105
00106
00107
00108 void Loader::
00109 output(ostream &out) const {
00110 out << get_type() << " " << get_name();
00111
00112 int num_tasks = _task_manager->make_task_chain(_task_chain)->get_num_tasks();
00113 if (num_tasks != 0) {
00114 out << " (" << num_tasks << " models pending)";
00115 }
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 PT(PandaNode) Loader::
00130 load_file(const Filename &filename, const LoaderOptions &options) const {
00131 Filename this_filename(filename);
00132 LoaderOptions this_options(options);
00133
00134 bool report_errors = (this_options.get_flags() & LoaderOptions::LF_report_errors) != 0;
00135
00136 string extension = this_filename.get_extension();
00137 if (extension.empty()) {
00138
00139
00140 this_filename = this_filename.get_fullpath() + default_model_extension.get_value();
00141 extension = this_filename.get_extension();
00142 }
00143
00144 bool pz_file = false;
00145 #ifdef HAVE_ZLIB
00146 if (extension == "pz") {
00147 pz_file = true;
00148 extension = Filename(this_filename.get_basename_wo_extension()).get_extension();
00149 }
00150 #endif // HAVE_ZLIB
00151
00152 if (extension.empty()) {
00153 if (report_errors) {
00154 loader_cat.error()
00155 << "Cannot load " << this_filename
00156 << " without filename extension. Loading of model filenames with an "
00157 "implicit extension is deprecated in Panda3D. Please "
00158 "correct the filename reference. If necessary, you may put the "
00159 "line \"default-model-extension .bam\" or \"default-model-extension .egg\" "
00160 "in your Config.prc to globally assume a particular model "
00161 "filename extension.\n";
00162 }
00163 return NULL;
00164 }
00165
00166 LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
00167 LoaderFileType *requested_type =
00168 reg->get_type_from_extension(extension);
00169 if (requested_type == (LoaderFileType *)NULL) {
00170 if (report_errors) {
00171 loader_cat.error()
00172 << "Extension of file " << this_filename
00173 << " is unrecognized; cannot load.\n";
00174 loader_cat.error(false)
00175 << "Currently known scene file types are:\n";
00176 reg->write(loader_cat.error(false), 2);
00177 }
00178 return NULL;
00179 } else if (pz_file && !requested_type->supports_compressed()) {
00180 if (report_errors) {
00181 loader_cat.error()
00182 << requested_type->get_name() << " file type (."
00183 << extension << ") does not support in-line compression.\n";
00184 }
00185 return NULL;
00186 }
00187
00188 bool search = (this_options.get_flags() & LoaderOptions::LF_search) != 0;
00189 if (!filename.is_local()) {
00190
00191 search = false;
00192 }
00193
00194
00195
00196 this_options.set_flags(this_options.get_flags() & ~LoaderOptions::LF_search);
00197
00198 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00199
00200 if (search) {
00201
00202 const ConfigVariableSearchPath &model_path = get_model_path();
00203 int num_dirs = model_path.get_num_directories();
00204 for (int i = 0; i < num_dirs; ++i) {
00205 Filename pathname(model_path.get_directory(i), this_filename);
00206 PT(PandaNode) result = try_load_file(pathname, this_options,
00207 requested_type);
00208 if (result != (PandaNode *)NULL) {
00209 return result;
00210 }
00211 }
00212
00213 if (report_errors) {
00214 bool any_exist = false;
00215 for (int i = 0; i < num_dirs; ++i) {
00216 Filename pathname(model_path.get_directory(i), this_filename);
00217 if (vfs->exists(pathname)) {
00218 any_exist = true;
00219 break;
00220 }
00221 }
00222
00223 if (any_exist) {
00224 loader_cat.error()
00225 << "Couldn't load file " << this_filename
00226 << ": all matching files on model path invalid "
00227 << "(the model path is currently: \"" << get_model_path() << "\")\n";
00228 } else {
00229 loader_cat.error()
00230 << "Couldn't load file " << this_filename
00231 << ": not found on model path "
00232 << "(currently: \"" << get_model_path() << "\")\n";
00233 }
00234 }
00235
00236 } else {
00237
00238 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00239 PT(PandaNode) result = try_load_file(this_filename, this_options, requested_type);
00240 if (result != (PandaNode *)NULL) {
00241 return result;
00242 }
00243 if (report_errors) {
00244 if (vfs->exists(this_filename)) {
00245 loader_cat.error()
00246 << "Couldn't load file " << this_filename << ": invalid.\n";
00247 } else {
00248 loader_cat.error()
00249 << "Couldn't load file " << this_filename << ": does not exist.\n";
00250 }
00251 }
00252 }
00253 return NULL;
00254 }
00255
00256
00257
00258
00259
00260
00261
00262
00263 PT(PandaNode) Loader::
00264 try_load_file(const Filename &pathname, const LoaderOptions &options,
00265 LoaderFileType *requested_type) const {
00266 BamCache *cache = BamCache::get_global_ptr();
00267
00268 bool cache_only = (options.get_flags() & LoaderOptions::LF_cache_only) != 0;
00269
00270 if (requested_type->get_allow_ram_cache(options)) {
00271
00272
00273 if (!cache_only || ModelPool::has_model(pathname)) {
00274 PT(PandaNode) node = ModelPool::load_model(pathname, options);
00275 if (node != (PandaNode *)NULL &&
00276 (options.get_flags() & LoaderOptions::LF_allow_instance) == 0) {
00277 if (loader_cat.is_debug()) {
00278 loader_cat.debug()
00279 << "Model " << pathname << " found in ModelPool.\n";
00280 }
00281
00282 node = node->copy_subgraph();
00283 }
00284 return node;
00285 }
00286 }
00287
00288 bool report_errors = ((options.get_flags() & LoaderOptions::LF_report_errors) != 0 || loader_cat.is_debug());
00289
00290 PT(BamCacheRecord) record;
00291 if (cache->get_cache_models() && requested_type->get_allow_disk_cache(options)) {
00292
00293
00294 record = cache->lookup(pathname, "bam");
00295 if (record != (BamCacheRecord *)NULL) {
00296 if (record->has_data()) {
00297 if (report_errors) {
00298 loader_cat.info()
00299 << "Model " << pathname << " found in disk cache.\n";
00300 }
00301 PT(PandaNode) result = DCAST(PandaNode, record->get_data());
00302 if (premunge_data) {
00303 SceneGraphReducer sgr;
00304 sgr.premunge(result, RenderState::make_empty());
00305 }
00306 return result;
00307 }
00308 }
00309 }
00310
00311 if (loader_cat.is_debug()) {
00312 loader_cat.debug()
00313 << "Model " << pathname << " not found in cache.\n";
00314 }
00315
00316 if (!cache_only) {
00317 PT(PandaNode) result = requested_type->load_file(pathname, options, record);
00318 if (result != (PandaNode *)NULL){
00319 if (record != (BamCacheRecord *)NULL) {
00320 record->set_data(result, result);
00321 cache->store(record);
00322 }
00323
00324 if (premunge_data) {
00325 SceneGraphReducer sgr;
00326 sgr.premunge(result, RenderState::make_empty());
00327 }
00328 return result;
00329 }
00330 }
00331
00332 return NULL;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 void Loader::
00345 load_file_types() {
00346 if (!_file_types_loaded) {
00347 int num_unique_values = load_file_type.get_num_unique_values();
00348
00349 for (int i = 0; i < num_unique_values; i++) {
00350 string param = load_file_type.get_unique_value(i);
00351
00352 vector_string words;
00353 extract_words(param, words);
00354
00355 if (words.size() == 1) {
00356
00357 string name = words[0];
00358 Filename dlname = Filename::dso_filename("lib" + name + ".so");
00359 loader_cat.info()
00360 << "loading file type module: " << name << endl;
00361 void *tmp = load_dso(get_plugin_path().get_value(), dlname);
00362 if (tmp == (void *)NULL) {
00363 loader_cat.warning()
00364 << "Unable to load " << dlname.to_os_specific()
00365 << ": " << load_dso_error() << endl;
00366 }
00367
00368 } else if (words.size() > 1) {
00369
00370
00371
00372 LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_global_ptr();
00373 size_t num_extensions = words.size() - 1;
00374 string library_name = words[num_extensions];
00375
00376 for (size_t i = 0; i < num_extensions; i++) {
00377 string extension = words[i];
00378 if (extension[0] == '.') {
00379 extension = extension.substr(1);
00380 }
00381
00382 registry->register_deferred_type(extension, library_name);
00383 }
00384 }
00385 }
00386
00387 _file_types_loaded = true;
00388 }
00389 }
00390
00391
00392
00393
00394
00395
00396
00397 void Loader::
00398 make_global_ptr() {
00399 nassertv(_global_ptr == (Loader *)NULL);
00400
00401 _global_ptr = new Loader("loader");
00402 }
00403