2
0
Эх сурвалжийг харах

support deferred loading of loader file types

David Rose 22 жил өмнө
parent
commit
25a599e3c9

+ 41 - 8
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 <algorithm>
 
 
@@ -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<string> 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;
   }
 }

+ 12 - 0
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

+ 1 - 0
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;
 

+ 114 - 11
panda/src/pgraph/loaderFileTypeRegistry.cxx

@@ -20,8 +20,8 @@
 #include "loaderFileType.h"
 #include "config_pgraph.h"
 
-#include <string_utils.h>
-#include <indent.h>
+#include "string_utils.h"
+#include "indent.h"
 
 #include <algorithm>
 
@@ -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());
+  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(extension);
+  ei = _extensions.find(dcextension);
   if (ei != _extensions.end()) {
-    loader_cat.warning()
+    // 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 "
-      << extension << "\n";
+      << dcextension << "\n";
   } else {
-    _extensions.insert(Extensions::value_type(extension, type));
+    _extensions.insert(Extensions::value_type(dcextension, type));
   }
+
+  _deferred_types.erase(dcextension);
 }

+ 9 - 2
panda/src/pgraph/loaderFileTypeRegistry.h

@@ -19,7 +19,7 @@
 #ifndef LOADERFILETYPEREGISTRY_H
 #define LOADERFILETYPEREGISTRY_H
 
-#include <pandabase.h>
+#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<LoaderFileType *> Types;
@@ -57,6 +61,9 @@ private:
   typedef pmap<string, LoaderFileType *> Extensions;
   Extensions _extensions;
 
+  typedef pmap<string, string> DeferredTypes;
+  DeferredTypes _deferred_types;
+
   static LoaderFileTypeRegistry *_global_ptr;
 };
 

+ 12 - 0
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

+ 1 - 0
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;
 

+ 12 - 0
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

+ 1 - 0
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);

+ 18 - 1
pandatool/src/mayaprogs/Sources.pp

@@ -94,4 +94,21 @@
     mayaPview.cxx mayaPview.h
 
 #end lib_target
-  
+
+#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

+ 1 - 5
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

+ 2 - 2
pandatool/src/ptloader/config_ptloader.h

@@ -19,9 +19,9 @@
 #ifndef CONFIG_PTLOADER_H
 #define CONFIG_PTLOADER_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <dconfig.h>
+#include "dconfig.h"
 
 ConfigureDecl(config_ptloader, EXPCL_PTLOADER, EXPTP_PTLOADER);
 

+ 12 - 0
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

+ 1 - 0
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;