diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 82e119504f..ca3cd93e8c 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -31,9 +31,10 @@ #include "circBuffer.h" #include "filename.h" #include "load_dso.h" - +#include "string_utils.h" #include "plist.h" #include "pvector.h" + #include @@ -310,17 +311,49 @@ load_file_types() { nassertv(load_file_type != (Config::ConfigTable::Symbol *)NULL); if (!_file_types_loaded) { + + // When we use GetAll(), we might inadvertently read duplicate + // lines. Filter them out with a set. + pset already_read; + Config::ConfigTable::Symbol::iterator ti; for (ti = load_file_type->begin(); ti != load_file_type->end(); ++ti) { - Filename dlname = Filename::dso_filename("lib" + (*ti).Val() + ".so"); - loader_cat.info() - << "loading file type module: " << dlname.to_os_specific() << endl; - void *tmp = load_dso(dlname); - if (tmp == (void *)NULL) { - loader_cat.info() - << "Unable to load: " << load_dso_error() << endl; + string param = (*ti).Val(); + if (already_read.insert(param).second) { + vector_string words; + extract_words(param, words); + + if (words.size() == 1) { + // Exactly one word: load the named library immediately. + Filename dlname = Filename::dso_filename("lib" + words[0] + ".so"); + loader_cat.info() + << "loading file type module: " << dlname.to_os_specific() << endl; + void *tmp = load_dso(dlname); + if (tmp == (void *)NULL) { + loader_cat.info() + << "Unable to load: " << load_dso_error() << endl; + } + + } else if (words.size() > 1) { + // Multiple words: the first n words are filename extensions, + // and the last word is the name of the library to load should + // any of those filename extensions be encountered. + LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_ptr(); + size_t num_extensions = words.size() - 1; + string library_name = words[num_extensions]; + + for (size_t i = 0; i < num_extensions; i++) { + string extension = words[i]; + if (extension[0] == '.') { + extension = extension.substr(1); + } + + registry->register_deferred_type(extension, library_name); + } + } } } + _file_types_loaded = true; } } diff --git a/panda/src/pgraph/loaderFileType.cxx b/panda/src/pgraph/loaderFileType.cxx index 584019f486..fee71fab8c 100644 --- a/panda/src/pgraph/loaderFileType.cxx +++ b/panda/src/pgraph/loaderFileType.cxx @@ -38,6 +38,18 @@ LoaderFileType:: ~LoaderFileType() { } +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileType::get_additional_extensions +// Access: Public, Virtual +// Description: Returns a space-separated list of extension, in +// addition to the one returned by get_extension(), that +// are recognized by this loader. +//////////////////////////////////////////////////////////////////// +string LoaderFileType:: +get_additional_extensions() const { + return string(); +} + //////////////////////////////////////////////////////////////////// // Function: LoaderFileType::load_file // Access: Public, Virtual diff --git a/panda/src/pgraph/loaderFileType.h b/panda/src/pgraph/loaderFileType.h index 370a5d8e05..aae0d1f420 100644 --- a/panda/src/pgraph/loaderFileType.h +++ b/panda/src/pgraph/loaderFileType.h @@ -43,6 +43,7 @@ public: virtual string get_name() const=0; virtual string get_extension() const=0; + virtual string get_additional_extensions() const; virtual PT(PandaNode) load_file(const Filename &path, bool report_errors) const; diff --git a/panda/src/pgraph/loaderFileTypeRegistry.cxx b/panda/src/pgraph/loaderFileTypeRegistry.cxx index ebc9d5c8dc..6d34dafadf 100644 --- a/panda/src/pgraph/loaderFileTypeRegistry.cxx +++ b/panda/src/pgraph/loaderFileTypeRegistry.cxx @@ -20,8 +20,8 @@ #include "loaderFileType.h" #include "config_pgraph.h" -#include -#include +#include "string_utils.h" +#include "indent.h" #include @@ -88,11 +88,41 @@ get_type(int n) const { // the extension matches no known file types. //////////////////////////////////////////////////////////////////// LoaderFileType *LoaderFileTypeRegistry:: -get_type_from_extension(const string &extension) const { +get_type_from_extension(const string &extension) { + string dcextension = downcase(extension); + Extensions::const_iterator ei; - ei = _extensions.find(downcase(extension)); + ei = _extensions.find(dcextension); if (ei == _extensions.end()) { - // Nothing matches that extension. + // Nothing matches that extension. Do we have a deferred type? + + DeferredTypes::iterator di; + di = _deferred_types.find(dcextension); + if (di != _deferred_types.end()) { + // We do! Try to load the deferred library on-the-fly. Note + // that this is a race condition if we support threaded loading; + // this whole function needs to be protected from multiple + // entry. + Filename dlname = Filename::dso_filename("lib" + (*di).second + ".so"); + _deferred_types.erase(di); + + loader_cat->info() + << "loading file type module: " << dlname.to_os_specific() << endl; + void *tmp = load_dso(dlname); + if (tmp == (void *)NULL) { + loader_cat->info() + << "Unable to load: " << load_dso_error() << endl; + return NULL; + } + + // Now try again to find the LoaderFileType. + ei = _extensions.find(dcextension); + } + } + + if (ei == _extensions.end()) { + // Nothing matches that extension, even after we've checked for a + // deferred type description. return NULL; } @@ -119,6 +149,16 @@ write_types(ostream &out, int indent_level) const { << " ." << type->get_extension() << "\n"; } } + + if (!_deferred_types.empty()) { + indent(out, indent_level) << "Also available:"; + DeferredTypes::const_iterator di; + for (di = _deferred_types.begin(); di != _deferred_types.end(); ++di) { + const string &extension = (*di).first; + out << " ." << extension; + } + out << "\n"; + } } //////////////////////////////////////////////////////////////////// @@ -130,7 +170,7 @@ void LoaderFileTypeRegistry:: register_type(LoaderFileType *type) { // Make sure we haven't already registered this type. if (find(_types.begin(), _types.end(), type) != _types.end()) { - loader_cat.warning() + loader_cat->info() << "Attempt to register LoaderFileType " << type->get_name() << " (" << type->get_type() << ") more than once.\n"; return; @@ -138,14 +178,77 @@ register_type(LoaderFileType *type) { _types.push_back(type); - string extension = downcase(type->get_extension()); - Extensions::const_iterator ei; - ei = _extensions.find(extension); - if (ei != _extensions.end()) { - loader_cat.warning() - << "Multiple LoaderFileTypes registered that use the extension " - << extension << "\n"; - } else { - _extensions.insert(Extensions::value_type(extension, type)); + record_extension(type->get_extension(), type); + + vector_string words; + extract_words(type->get_additional_extensions(), words); + vector_string::const_iterator wi; + for (wi = words.begin(); wi != words.end(); ++wi) { + record_extension(*wi, type); } } + +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileTypeRegistry::register_deferred_type +// Access: Public +// Description: Records a type associated with a particular extension +// to be loaded in the future. The named library will +// be dynamically loaded the first time files of this +// extension are loaded; presumably this library will +// call register_type() when it initializes, thus making +// the extension loadable. +//////////////////////////////////////////////////////////////////// +void LoaderFileTypeRegistry:: +register_deferred_type(const string &extension, const string &library) { + string dcextension = downcase(extension); + + Extensions::const_iterator ei; + ei = _extensions.find(dcextension); + if (ei != _extensions.end()) { + // We already have a loader for this type; no need to register + // another one. + loader_cat->info() + << "Attempt to register loader library " << library + << " (" << dcextension << ") when extension is already known.\n"; + return; + } + + DeferredTypes::const_iterator di; + di = _deferred_types.find(dcextension); + if (di != _deferred_types.end()) { + if ((*di).second == library) { + loader_cat->info() + << "Attempt to register loader library " << library + << " (" << dcextension << ") more than once.\n"; + return; + } else { + loader_cat->info() + << "Multiple libraries registered that use the extension " + << dcextension << "\n"; + } + } + + _deferred_types[dcextension] = library; +} + +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileTypeRegistry::record_extension +// Access: Private +// Description: Records a filename extension recognized by a loader +// file type. +//////////////////////////////////////////////////////////////////// +void LoaderFileTypeRegistry:: +record_extension(const string &extension, LoaderFileType *type) { + string dcextension = downcase(extension); + Extensions::const_iterator ei; + ei = _extensions.find(dcextension); + if (ei != _extensions.end()) { + loader_cat->info() + << "Multiple LoaderFileTypes registered that use the extension " + << dcextension << "\n"; + } else { + _extensions.insert(Extensions::value_type(dcextension, type)); + } + + _deferred_types.erase(dcextension); +} diff --git a/panda/src/pgraph/loaderFileTypeRegistry.h b/panda/src/pgraph/loaderFileTypeRegistry.h index 4a17175d82..9b5b281715 100644 --- a/panda/src/pgraph/loaderFileTypeRegistry.h +++ b/panda/src/pgraph/loaderFileTypeRegistry.h @@ -19,7 +19,7 @@ #ifndef LOADERFILETYPEREGISTRY_H #define LOADERFILETYPEREGISTRY_H -#include +#include "pandabase.h" #include "pvector.h" #include "pmap.h" @@ -44,11 +44,15 @@ public: int get_num_types() const; LoaderFileType *get_type(int n) const; - LoaderFileType *get_type_from_extension(const string &extension) const; + LoaderFileType *get_type_from_extension(const string &extension); void write_types(ostream &out, int indent_level = 0) const; void register_type(LoaderFileType *type); + void register_deferred_type(const string &extension, const string &library); + +private: + void record_extension(const string &extension, LoaderFileType *type); private: typedef pvector Types; @@ -57,6 +61,9 @@ private: typedef pmap Extensions; Extensions _extensions; + typedef pmap DeferredTypes; + DeferredTypes _deferred_types; + static LoaderFileTypeRegistry *_global_ptr; }; diff --git a/pandatool/src/converter/somethingToEggConverter.cxx b/pandatool/src/converter/somethingToEggConverter.cxx index 5486c63c2c..2200aeecdd 100644 --- a/pandatool/src/converter/somethingToEggConverter.cxx +++ b/pandatool/src/converter/somethingToEggConverter.cxx @@ -90,6 +90,18 @@ set_egg_data(EggData *egg_data, bool owns_egg_data) { _owns_egg_data = owns_egg_data; } +//////////////////////////////////////////////////////////////////// +// Function: SomethingToEggConverter::get_additional_extensions +// Access: Public, Virtual +// Description: Returns a space-separated list of extension, in +// addition to the one returned by get_extension(), that +// are recognized by this converter. +//////////////////////////////////////////////////////////////////// +string SomethingToEggConverter:: +get_additional_extensions() const { + return string(); +} + //////////////////////////////////////////////////////////////////// // Function: SomethingToEggConverter::handle_external_reference // Access: Public diff --git a/pandatool/src/converter/somethingToEggConverter.h b/pandatool/src/converter/somethingToEggConverter.h index 93829a2aaf..046f155e77 100644 --- a/pandatool/src/converter/somethingToEggConverter.h +++ b/pandatool/src/converter/somethingToEggConverter.h @@ -101,6 +101,7 @@ public: virtual string get_name() const=0; virtual string get_extension() const=0; + virtual string get_additional_extensions() const; virtual bool convert_file(const Filename &filename)=0; diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index ca557507ba..756ed8ba88 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -151,6 +151,18 @@ get_extension() const { return "mb"; } +//////////////////////////////////////////////////////////////////// +// Function: MayaToEggConverter::get_additional_extensions +// Access: Public, Virtual +// Description: Returns a space-separated list of extension, in +// addition to the one returned by get_extension(), that +// are recognized by this converter. +//////////////////////////////////////////////////////////////////// +string MayaToEggConverter:: +get_additional_extensions() const { + return "ma"; +} + //////////////////////////////////////////////////////////////////// // Function: MayaToEggConverter::convert_file // Access: Public, Virtual diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h index c12afc04af..d79fc2e2b4 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ b/pandatool/src/mayaegg/mayaToEggConverter.h @@ -70,6 +70,7 @@ public: virtual string get_name() const; virtual string get_extension() const; + virtual string get_additional_extensions() const; virtual bool convert_file(const Filename &filename); bool convert_maya(bool from_selection); diff --git a/pandatool/src/mayaprogs/Sources.pp b/pandatool/src/mayaprogs/Sources.pp index 2238f38dd3..947e1ad939 100644 --- a/pandatool/src/mayaprogs/Sources.pp +++ b/pandatool/src/mayaprogs/Sources.pp @@ -94,4 +94,21 @@ mayaPview.cxx mayaPview.h #end lib_target - \ No newline at end of file + +#begin lib_target + #define USE_PACKAGES maya + #define TARGET mayaloader + #define BUILDING_DLL BUILDING_MISC + #define LOCAL_LIBS \ + mayaegg ptloader converter pandatoolbase + #define OTHER_LIBS \ + egg2pg:c builder:c egg:c pandaegg:m \ + mathutil:c linmath:c putil:c panda:m \ + express:c pandaexpress:m \ + dtoolconfig dtool \ + $[if $[UNIX_PLATFORM],OpenMayalib] + + #define SOURCES \ + config_mayaloader.cxx + +#end lib_target diff --git a/pandatool/src/ptloader/Sources.pp b/pandatool/src/ptloader/Sources.pp index 6f4f8c1864..f62072e568 100644 --- a/pandatool/src/ptloader/Sources.pp +++ b/pandatool/src/ptloader/Sources.pp @@ -2,7 +2,7 @@ #define TARGET ptloader #define BUILDING_DLL BUILDING_PTLOADER #define LOCAL_LIBS \ - fltegg flt lwoegg lwo mayaegg converter pandatoolbase + fltegg flt lwoegg lwo converter pandatoolbase #define OTHER_LIBS \ egg2pg:c builder:c egg:c pandaegg:m \ mathutil:c linmath:c putil:c panda:m \ @@ -11,10 +11,6 @@ #define UNIX_SYS_LIBS \ m - // If we've got Maya, link in the Maya libraries. - // On second thought, don't. It takes forever to load. - //#define USE_PACKAGES maya - #define SOURCES \ config_ptloader.cxx config_ptloader.h \ loaderFileTypePandatool.cxx loaderFileTypePandatool.h diff --git a/pandatool/src/ptloader/config_ptloader.h b/pandatool/src/ptloader/config_ptloader.h index 2a3401594d..7bc4a2990c 100644 --- a/pandatool/src/ptloader/config_ptloader.h +++ b/pandatool/src/ptloader/config_ptloader.h @@ -19,9 +19,9 @@ #ifndef CONFIG_PTLOADER_H #define CONFIG_PTLOADER_H -#include +#include "pandatoolbase.h" -#include +#include "dconfig.h" ConfigureDecl(config_ptloader, EXPCL_PTLOADER, EXPTP_PTLOADER); diff --git a/pandatool/src/ptloader/loaderFileTypePandatool.cxx b/pandatool/src/ptloader/loaderFileTypePandatool.cxx index 109ce2080a..936db924b7 100644 --- a/pandatool/src/ptloader/loaderFileTypePandatool.cxx +++ b/pandatool/src/ptloader/loaderFileTypePandatool.cxx @@ -66,6 +66,18 @@ get_extension() const { return _converter->get_extension(); } +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileTypePandatool::get_additional_extensions +// Access: Public, Virtual +// Description: Returns a space-separated list of extension, in +// addition to the one returned by get_extension(), that +// are recognized by this converter. +//////////////////////////////////////////////////////////////////// +string LoaderFileTypePandatool:: +get_additional_extensions() const { + return _converter->get_additional_extensions(); +} + //////////////////////////////////////////////////////////////////// // Function: LoaderFileTypePandatool::resolve_filename // Access: Public, Virtual diff --git a/pandatool/src/ptloader/loaderFileTypePandatool.h b/pandatool/src/ptloader/loaderFileTypePandatool.h index 7f65932214..c6f681ee84 100644 --- a/pandatool/src/ptloader/loaderFileTypePandatool.h +++ b/pandatool/src/ptloader/loaderFileTypePandatool.h @@ -39,6 +39,7 @@ public: virtual string get_name() const; virtual string get_extension() const; + virtual string get_additional_extensions() const; virtual void resolve_filename(Filename &path) const; virtual PT(PandaNode) load_file(const Filename &path, bool report_errors) const;