Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pgraph/loader.cxx

Go to the documentation of this file.
00001 // Filename: loader.cxx
00002 // Created by:  mike (09Jan97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "loader.h"
00020 #include "loaderFileType.h"
00021 #include "loaderFileTypeRegistry.h"
00022 #include "config_pgraph.h"
00023 
00024 #include "config_express.h"
00025 #include "config_util.h"
00026 #include "virtualFileSystem.h"
00027 #include "event.h"
00028 #include "pt_Event.h"
00029 #include "throw_event.h"
00030 #include "eventParameter.h"
00031 #include "circBuffer.h"
00032 #include "filename.h"
00033 #include "load_dso.h"
00034 
00035 #include "plist.h"
00036 #include "pvector.h"
00037 #include <algorithm>
00038 
00039 
00040 bool Loader::_file_types_loaded = false;
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //      Struct : LoaderToken
00044 // Description : Holds a request for the loader (load or delete), as
00045 //               well as the return information after the request has
00046 //               completed.
00047 ////////////////////////////////////////////////////////////////////
00048 class LoaderToken : public ReferenceCount {
00049 public:
00050   INLINE LoaderToken(uint id, const string &event_name, const Filename &path, 
00051                      bool search, PandaNode *node=NULL) : 
00052     _id(id), 
00053     _event_name(event_name), 
00054     _path(path),
00055     _search(search),
00056     _node(node) 
00057   { }
00058   uint _id;
00059   string _event_name;
00060   Filename _path;
00061   bool _search;
00062   PT(PandaNode) _node;
00063 };
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: Loader::Constructor
00067 //       Access: Published
00068 //  Description:
00069 ////////////////////////////////////////////////////////////////////
00070 Loader::
00071 Loader() : AsyncUtility() {
00072   _token_board = new LoaderTokenBoard;
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: Loader::Destructor
00077 //       Access: Published
00078 //  Description:
00079 ////////////////////////////////////////////////////////////////////
00080 Loader::
00081 ~Loader() {
00082   destroy_thread();
00083   delete _token_board;
00084 }
00085 
00086 ////////////////////////////////////////////////////////////////////
00087 //     Function: Loader::find_all_files
00088 //       Access: Published
00089 //  Description: Searches along the given search path for the given
00090 //               file name, and fills up the results list with all
00091 //               possible matches and their associated types, in
00092 //               order.
00093 ////////////////////////////////////////////////////////////////////
00094 int Loader::
00095 find_all_files(const Filename &filename, const DSearchPath &search_path,
00096                Loader::Results &results) const {
00097   if (!_file_types_loaded) {
00098     load_file_types();
00099   }
00100   string extension = filename.get_extension();
00101 
00102   int num_added = 0;
00103 
00104   if (!extension.empty()) {
00105     // If the extension is not empty, it specifies a single file type.
00106     LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr();
00107     LoaderFileType *requested_type =
00108       reg->get_type_from_extension(extension);
00109 
00110     if (requested_type != (LoaderFileType *)NULL) {
00111       if (!filename.is_local()) {
00112         // Global filename, take it as it is.
00113         results.add_file(filename, requested_type);
00114         num_added++;
00115 
00116       } else {
00117         // Local filename, search along the path.
00118         DSearchPath::Results files;
00119         if (use_vfs) {
00120           VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00121           num_added = vfs->find_all_files(filename, search_path, files);
00122         } else {
00123           num_added = search_path.find_all_files(filename, files);
00124         }
00125         
00126         for (int i = 0; i < num_added; i++) {
00127           results.add_file(files.get_file(i), requested_type);
00128         }
00129       }
00130     }
00131 
00132   } else {
00133     // If the extension *is* empty, we have to search for all possible
00134     // file types.
00135     LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr();
00136     int num_types = reg->get_num_types();
00137 
00138     if (!filename.is_local()) {
00139       // Global filename, take it as it is.
00140       for (int t = 0; t < num_types; t++) {
00141         LoaderFileType *type = reg->get_type(t);
00142         Filename file(filename);
00143         file.set_extension(type->get_extension());
00144           
00145         if (use_vfs) {
00146           VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00147           if (vfs->exists(file)) {
00148             results.add_file(file, type);
00149             num_added++;
00150           }
00151         } else {
00152           if (file.exists()) {
00153             results.add_file(file, type);
00154             num_added++;
00155           }
00156         }
00157       }
00158 
00159     } else {
00160       // Local filename, look it up on the model path.
00161       int num_dirs = search_path.get_num_directories();
00162       for (int i = 0; i < num_dirs; i++) {
00163         const Filename &directory = search_path.get_directory(i);
00164         
00165         for (int t = 0; t < num_types; t++) {
00166           LoaderFileType *type = reg->get_type(t);
00167           Filename file(directory, filename);
00168           file.set_extension(type->get_extension());
00169           
00170           if (use_vfs) {
00171             VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00172             if (vfs->exists(file)) {
00173               results.add_file(file, type);
00174               num_added++;
00175             }
00176           } else {
00177             if (file.exists()) {
00178               results.add_file(file, type);
00179               num_added++;
00180             }
00181           }
00182         }
00183       }
00184     }
00185   }
00186 
00187   return num_added;
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: Loader::request_load
00192 //       Access: Published
00193 //  Description: Requests an asynchronous load of a file.  The request
00194 //               will be queued and served by the asynchronous thread.
00195 //               If event_name is nonempty, it is the name of the
00196 //               event that will be thrown (with the uint id as its
00197 //               single parameter) when the loading is completed later.
00198 //
00199 //               The return value is an integer which can be used to
00200 //               identify this particular request later to
00201 //               fetch_load(), or 0 if there has been an error.
00202 //
00203 //               If search is true, the file is searched for along the
00204 //               model path; otherwise, only the exact filename is
00205 //               loaded.
00206 ////////////////////////////////////////////////////////////////////
00207 uint Loader::
00208 request_load(const string &event_name, const Filename &filename, bool search) {
00209   if (!_file_types_loaded) {
00210     load_file_types();
00211   }
00212 
00213   PT(LoaderToken) tok;
00214   if (asynchronous_loads) {
00215 
00216     // Make sure we actually are threaded
00217     if (!_threaded) {
00218       loader_cat.info()
00219         << "Loader::request_load() - create_thread() was "
00220         << "never called!  Calling it now..." << endl;
00221       create_thread();
00222     }
00223 
00224     // We need to grab the lock in order to signal the condition variable
00225 #ifdef OLD_HAVE_IPC
00226     _lock.lock();
00227 #endif
00228 
00229       if (_token_board->_waiting.full()) {
00230         loader_cat.error()
00231           << "Loader::request_load() - Too many pending requests\n";
00232         return 0;
00233       }
00234 
00235       if (loader_cat.is_debug()) {
00236         loader_cat.debug()
00237           << "Load requested for file: " << filename << "\n";
00238       }
00239 
00240       tok = new LoaderToken(_next_token++, event_name, filename, search);
00241       _token_board->_waiting.push_back(tok);
00242 
00243 #ifdef OLD_HAVE_IPC
00244       _request_cond->signal();
00245     _lock.unlock();
00246 #endif
00247 
00248   } else {
00249     // If we're not running asynchronously, process the load request
00250     // directly now.
00251     if (_token_board->_waiting.full()) {
00252       loader_cat.error()
00253         << "Loader::request_load() - Too many pending requests\n";
00254       return 0;
00255     }
00256 
00257     if (loader_cat.is_debug()) {
00258       loader_cat.debug()
00259         << "Load requested for file: " << filename << "\n";
00260     }
00261 
00262     tok = new LoaderToken(_next_token++, event_name, filename, search);
00263     _token_board->_waiting.push_back(tok);
00264     process_request();
00265   }
00266 
00267   return tok->_id;
00268 }
00269 
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: Loader::check_load
00272 //       Access: Published
00273 //  Description: Returns true if the indicated load-request has
00274 //               completed and not yet been fetched, false otherwise.
00275 ////////////////////////////////////////////////////////////////////
00276 bool Loader::
00277 check_load(uint id) {
00278   return _token_board->is_done_token(id);
00279 }
00280 
00281 ////////////////////////////////////////////////////////////////////
00282 //     Function: Loader::fetch_load
00283 //       Access: Published
00284 //  Description: Returns the Node associated with the indicated id
00285 //               number (returned by a previous call to request_load),
00286 //               or NULL if the request has not yet completed.
00287 ////////////////////////////////////////////////////////////////////
00288 PT(PandaNode) Loader::
00289 fetch_load(uint id) {
00290   PT(LoaderToken) tok = _token_board->get_done_token(id);
00291   if (tok.is_null()) {
00292     loader_cat.debug()
00293       << "Request to fetch id " << id << " which has not yet completed.\n";
00294     return NULL;
00295   }
00296   PT(PandaNode) node = tok->_node;
00297   return node;
00298 }
00299 
00300 ////////////////////////////////////////////////////////////////////
00301 //     Function: Loader::load_file_types
00302 //       Access: Private, Static
00303 //  Description: Loads up all of the dynamic libraries named in a
00304 //               load-file-type Configure variable.  Presumably this
00305 //               will make the various file types available for
00306 //               runtime loading.
00307 ////////////////////////////////////////////////////////////////////
00308 void Loader::
00309 load_file_types() {
00310   nassertv(load_file_type != (Config::ConfigTable::Symbol *)NULL);
00311 
00312   if (!_file_types_loaded) {
00313     Config::ConfigTable::Symbol::iterator ti;
00314     for (ti = load_file_type->begin(); ti != load_file_type->end(); ++ti) {
00315       Filename dlname = Filename::dso_filename("lib" + (*ti).Val() + ".so");
00316       loader_cat.info()
00317         << "loading file type module: " << dlname.to_os_specific() << endl;
00318       void *tmp = load_dso(dlname);
00319       if (tmp == (void *)NULL) {
00320         loader_cat.info()
00321           << "Unable to load: " << load_dso_error() << endl;
00322       }
00323     }
00324     _file_types_loaded = true;
00325   }
00326 }
00327 
00328 ////////////////////////////////////////////////////////////////////
00329 //     Function: Loader::process_request
00330 //       Access: Private
00331 //  Description: Serves any requests on the token board, moving them
00332 //               to the done queue.
00333 ////////////////////////////////////////////////////////////////////
00334 bool Loader::
00335 process_request() {
00336   if (_shutdown) {
00337     if (loader_cat.is_debug())
00338       loader_cat.debug()
00339           << "Loader shutting down...\n";
00340     return false;
00341   }
00342 
00343   // If there is actually a request token - process it
00344   while (!_token_board->_waiting.empty()) {
00345     PT(LoaderToken) tok = _token_board->_waiting.front();
00346     _token_board->_waiting.pop_front();
00347     tok->_node = load_file(tok->_path, tok->_search);
00348     if (tok->_node == (PandaNode *)NULL) {
00349       loader_cat.error()
00350         << "Loader::callback() - couldn't find file: "
00351         << tok->_path << "\n";
00352     } else {
00353       _token_board->_done.push_back(tok);
00354 
00355       // Throw a "done" event now.
00356       if (!tok->_event_name.empty()) {
00357         PT_Event done = new Event(tok->_event_name);
00358         done->add_parameter(EventParameter((int)tok->_id));
00359         throw_event(done);
00360       }
00361     }
00362 
00363     if (loader_cat.is_debug()) {
00364       loader_cat.debug()
00365         << "loading complete for " << tok->_path << "\n";
00366     }
00367   }
00368 
00369   return true;
00370 }
00371 
00372 ////////////////////////////////////////////////////////////////////
00373 //     Function: Loader::load_file
00374 //       Access: Private
00375 //  Description: Loads a single scene graph file, if possible.
00376 //               Returns the Node that is the root of the file, or
00377 //               NULL if the file cannot be loaded.
00378 //
00379 //               If search is true, the file is searched for along the
00380 //               model path; otherwise, only the exact filename is
00381 //               loaded.
00382 ////////////////////////////////////////////////////////////////////
00383 PT(PandaNode) Loader::
00384 load_file(const Filename &filename, bool search) const {
00385   Results results;
00386   int num_files;
00387 
00388   if (search) {
00389     // Look for the file along the model path.
00390     num_files = find_all_files(filename, get_model_path(), results);
00391   } else {
00392     // Look for the file only where it is.
00393     num_files = find_all_files(filename, DSearchPath("."), results);
00394   }
00395 
00396   if (num_files == 0) {
00397     // Couldn't find the file.  Either it doesn't exist, or it's an
00398     // unknown file type.  Report a useful message either way.
00399     string extension = filename.get_extension();
00400     if (!extension.empty()) {
00401       LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr();
00402       LoaderFileType *requested_type =
00403         reg->get_type_from_extension(extension);
00404       if (requested_type == (LoaderFileType *)NULL) {
00405         loader_cat.error()
00406           << "Extension of file " << filename
00407           << " is unrecognized; cannot load.\n";
00408         loader_cat.error(false)
00409           << "Currently known scene file types are:\n";
00410         reg->write_types(loader_cat.error(false), 2);
00411         return NULL;
00412       }
00413     }
00414 
00415     if (search) {
00416       loader_cat.error()
00417         << "Couldn't load file " << filename << ": not found on model path.\n";
00418 
00419     } else {
00420       loader_cat.error()
00421         << "Couldn't load file " << filename << ": does not exist.\n";
00422     }
00423     return NULL;
00424   }
00425 
00426   for (int i = 0; i < num_files; i++) {
00427     const Filename &path = results.get_file(i);
00428     LoaderFileType *type = results.get_file_type(i);
00429     PT(PandaNode) result = type->load_file(path, true);
00430     if (result != (PandaNode *)NULL) {
00431       return result;
00432     }
00433   }
00434 
00435   // None of the matching files could be loaded.  Oh well.
00436   if (search) {
00437     loader_cat.error()
00438       << "Couldn't load file " << filename
00439       << ": all matching files on model path invalid.\n";
00440 
00441   } else {
00442     loader_cat.error()
00443       << "Couldn't load file " << filename
00444       << ": invalid.\n";
00445   }
00446   return NULL;
00447 }
00448 

Generated on Fri May 2 00:41:47 2003 for Panda by doxygen1.3