Browse Source

multiplatform support for plugin loader: run 32-bit or 64-bit version; whichever one is provided.

David Rose 13 years ago
parent
commit
0662ea7958

+ 4 - 0
direct/src/ffi/panda3d.py

@@ -124,6 +124,10 @@ class panda3d_import_manager:
                 if (cls.os.path.exists(lib + dll_ext)):
                     target = lib + dll_ext
                     break
+            if target:
+                # Once we find the first match, break all the way
+                # out--don't keep looking for a second match.
+                break
         if target == None:
             message = "DLL loader cannot find %s." % name
             raise ImportError, message

+ 5 - 11
direct/src/p3d/HostInfo.py

@@ -28,13 +28,9 @@ class HostInfo:
         there.  At the moment, mirror folders do not download old
         patch files from the server.
 
-        If you pass perPlatform = True, then files are unpacked into a
-        platform-specific directory, which is appropriate when you
-        might be downloading multiple platforms.  The default is
-        perPlatform = False, which means all files are unpacked into
-        the host directory directly, without an intervening
-        platform-specific directory name.  If asMirror is True, then
-        the default is perPlatform = True. """
+        perPlatform remains for historical reasons, but it is ignored.
+        Nowadays, all files are always unpacked into platform-specific
+        directories, even on the client. """
 
         assert appRunner or rootDir or hostDir
 
@@ -49,9 +45,7 @@ class HostInfo:
             
         self.hostDir = hostDir
         self.asMirror = asMirror
-        self.perPlatform = perPlatform
-        if perPlatform is None:
-            self.perPlatform = asMirror
+        self.perPlatform = True
 
         # Initially false, this is set true when the contents file is
         # successfully read.
@@ -583,7 +577,7 @@ class HostInfo:
                 for pkey, package in pitems:
                     result.append(package)
             else:
-                # If we maintain a a host for the current platform
+                # If we maintain a host for the current platform
                 # only (e.g. a client copy), then return only the
                 # current platform, or no particular platform.
                 package = platforms.get(PandaSystem.getPlatform(), None)

+ 8 - 0
direct/src/p3d/Packager.py

@@ -2197,6 +2197,14 @@ class Packager:
 
         # The system PATH, for searching dll's and exe's.
         self.executablePath = DSearchPath()
+
+        # By convention, we include sys.path at the front of
+        # self.executablePath, mainly to aid makepanda when building
+        # an rtdist build.
+        for dirname in sys.path:
+            self.executablePath.appendDirectory(Filename.fromOsSpecific(dirname))
+
+        # Now add the actual system search path.
         if self.platform.startswith('win'):
             self.addWindowsSearchPath(self.executablePath, "PATH")
         elif self.platform.startswith('osx'):

+ 0 - 1
direct/src/p3d/ppackage.py

@@ -241,7 +241,6 @@ for platform in platforms:
         # Just print the error message and exit gracefully.
         inst = sys.exc_info()[1]
         print inst.args[0]
-        #raise
         sys.exit(1)
 
 # An explicit call to exit() is required to exit the program, when

+ 160 - 37
direct/src/plugin/p3dHost.cxx

@@ -62,7 +62,11 @@ P3DHost::
     PackageMap &package_map = (*mi).second;
     PackageMap::iterator pi;
     for (pi = package_map.begin(); pi != package_map.end(); ++pi) {
-      delete (*pi).second;
+      PlatformPackages &ppackages = (*pi).second;
+      PlatformPackages::iterator ppi;
+      for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) {
+        delete (*ppi);
+      }
     }
   }
   _packages.clear();
@@ -356,14 +360,16 @@ read_xhost(TiXmlElement *xhost) {
 ////////////////////////////////////////////////////////////////////
 P3DPackage *P3DHost::
 get_package(const string &package_name, const string &package_version,
-            const string &package_seq, const string &alt_host) {
+            const string &package_platform, const string &package_seq, 
+            const string &alt_host) {
   if (!alt_host.empty()) {
     if (_xcontents != NULL) {
       // If we're asking for an alt host and we've already read our
       // contents.xml file, then we already know all of our hosts, and
       // we can start the package off with the correct host immediately.
       P3DHost *new_host = get_alt_host(alt_host);
-      return new_host->get_package(package_name, package_version, package_seq);
+      return new_host->get_package(package_name, package_version, 
+                                   package_platform, package_seq);
     }
 
     // If we haven't read contents.xml yet, we need to create the
@@ -371,30 +377,44 @@ get_package(const string &package_name, const string &package_version,
     // contents.xml, and it can migrate to its alt_host after that.
   }
 
-  PackageMap &package_map = _packages[alt_host];
-
+  string key = package_name + "_" + package_version;
+  PlatformPackages &ppackages = _packages[alt_host][key];
+  PlatformPackages::iterator ppi;
   P3DPackage *package = NULL;
 
-  string key = package_name + "_" + package_version;
-  PackageMap::iterator pi = package_map.find(key);
-  if (pi != package_map.end()) {
-    // We've previously installed this package.
-    package = (*pi).second;
+  // First, look for an exact match of the platform.
+  for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) {
+    if ((*ppi)->get_package_platform() == package_platform) {
+      package = *ppi;
+      break;
+    }
+  }
 
+  // If an exact match isn't found, look for a generic platform.
+  if (package == NULL) {
+    for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) {
+      if ((*ppi)->get_package_platform().empty()) {
+        package = *ppi;
+        break;
+      }
+    }
+  }
+
+  if (package != NULL) {
     if (package->get_failed()) {
       // If the package has previously failed, move it aside and try
       // again (maybe it just failed because the user interrupted it).
       nout << "Package " << key << " has previously failed; trying again.\n";
       _failed_packages.push_back(package);
-      (*pi).second = NULL;
+      ppackages.erase(ppi);
       package = NULL;
     }
   }
 
   if (package == NULL) {
     package = 
-      new P3DPackage(this, package_name, package_version, alt_host);
-    package_map[key] = package;
+      new P3DPackage(this, package_name, package_version, package_platform, alt_host);
+    ppackages.push_back(package);
   }
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
@@ -403,10 +423,10 @@ get_package(const string &package_name, const string &package_version,
     // believe we have a valid contents.xml file, then check the seq
     // value in the contents.
     FileSpec desc_file;
-    string platform, seq;
+    string seq;
     bool solo;
-    if (get_package_desc_file(desc_file, platform, seq, solo,
-                              package_name, package_version)) {
+    if (get_package_desc_file(desc_file, seq, solo,
+                              package_name, package_version, package_platform)) {
       nout << package_name << ": asked for seq " << package_seq
            << ", we have seq " << seq << "\n";
       if (compare_seq(package_seq, seq) > 0) {
@@ -421,6 +441,103 @@ get_package(const string &package_name, const string &package_version,
   return package;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::choose_suitable_platform
+//       Access: Public
+//  Description: Chooses the most appropriate platform for the
+//               indicated package (presumably the "panda3d" package),
+//               based on what this hardware supports and what is
+//               actually available.
+////////////////////////////////////////////////////////////////////
+bool P3DHost::
+choose_suitable_platform(string &selected_platform,
+                         const string &package_name,
+                         const string &package_version,
+                         const string &package_platform) {
+  if (_xcontents == NULL) {
+    return false;
+  }
+
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+
+  TiXmlElement *xpackage;
+
+  // For the "panda3d" package only, we allow searching for any
+  // available supported platform.
+  if (package_name == "panda3d" && package_platform == "") {
+    int num_supported_platforms = inst_mgr->get_num_supported_platforms();
+    for (int pi = 0; pi < num_supported_platforms; ++pi) {
+      string supported_platform = inst_mgr->get_supported_platform(pi);
+      xpackage = _xcontents->FirstChildElement("package");
+      while (xpackage != NULL) {
+        const char *name = xpackage->Attribute("name");
+        const char *platform = xpackage->Attribute("platform");
+        const char *version = xpackage->Attribute("version");
+        if (version == NULL) {
+          version = "";
+        }
+        if (name != NULL && platform != NULL &&
+            package_name == name && 
+            supported_platform == platform &&
+            package_version == version) {
+          // Here's the matching package definition.
+          selected_platform = platform;
+          return true;
+        }
+        
+        xpackage = xpackage->NextSiblingElement("package");
+      }
+    }
+  }
+
+  // Now, we look for an exact match for the current platform.
+  xpackage = _xcontents->FirstChildElement("package");
+  while (xpackage != NULL) {
+    const char *name = xpackage->Attribute("name");
+    const char *platform = xpackage->Attribute("platform");
+    const char *version = xpackage->Attribute("version");
+    if (version == NULL) {
+      version = "";
+    }
+    if (name != NULL && platform != NULL &&
+        package_name == name && 
+        package_platform == platform &&
+        package_version == version) {
+      // Here's the matching package definition.
+      selected_platform = platform;
+      return true;
+    }
+
+    xpackage = xpackage->NextSiblingElement("package");
+  }
+
+  // Look again, this time looking for a non-platform-specific version.
+  xpackage = _xcontents->FirstChildElement("package");
+  while (xpackage != NULL) {
+    const char *name = xpackage->Attribute("name");
+    const char *platform = xpackage->Attribute("platform");
+    const char *version = xpackage->Attribute("version");
+    if (platform == NULL) {
+      platform = "";
+    }
+    if (version == NULL) {
+      version = "";
+    }
+    if (name != NULL &&
+        package_name == name && 
+        *platform == '\0' &&
+        package_version == version) {
+      selected_platform = platform;
+      return true;
+    }
+
+    xpackage = xpackage->NextSiblingElement("package");
+  }
+
+  // Couldn't find a suitable platform.
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DHost::get_package_desc_file
 //       Access: Public
@@ -433,11 +550,11 @@ get_package(const string &package_name, const string &package_version,
 ////////////////////////////////////////////////////////////////////
 bool P3DHost::
 get_package_desc_file(FileSpec &desc_file,              // out
-                      string &package_platform,         // out
                       string &package_seq,              // out
                       bool &package_solo,               // out
                       const string &package_name,       // in
-                      const string &package_version) {  // in
+                      const string &package_version,    // in
+                      const string &package_platform) { // in
   if (_xcontents == NULL) {
     return false;
   }
@@ -461,12 +578,11 @@ get_package_desc_file(FileSpec &desc_file,              // out
     }
     if (name != NULL && platform != NULL &&
         package_name == name && 
-        inst_mgr->get_platform() == platform &&
+        package_platform == platform &&
         package_version == version) {
       // Here's the matching package definition.
       desc_file.load_xml(xpackage);
       package_seq = seq;
-      package_platform = platform;
       package_solo = false;
       if (solo != NULL) {
         package_solo = (atoi(solo) != 0);
@@ -501,7 +617,6 @@ get_package_desc_file(FileSpec &desc_file,              // out
       // Here's the matching package definition.
       desc_file.load_xml(xpackage);
       package_seq = seq;
-      package_platform = platform;
       package_solo = false;
       if (solo != NULL) {
         package_solo = (atoi(solo) != 0);
@@ -529,16 +644,19 @@ forget_package(P3DPackage *package, const string &alt_host) {
   string key = package->get_package_name() + "_" + package->get_package_version();
   nout << "Forgetting package " << key << "\n";
 
-  PackageMap &package_map = _packages[alt_host];
+  PlatformPackages &ppackages = _packages[alt_host][key];
 
-  // Hmm, this is a memory leak.  But we allow it to remain, since
-  // it's an unusual circumstance (uninstalling), and it's safer to
-  // leak than to risk a floating pointer.
-  package_map.erase(key);
+  PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package);
+  if (ppi != ppackages.end()) {
+    // Hmm, this is a memory leak.  But we allow it to remain, since
+    // it's an unusual circumstance (uninstalling), and it's safer to
+    // leak than to risk a floating pointer.
+    ppackages.erase(ppi);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DHost::migrate_package
+//     Function: P3DHost::migrate_package_host
 //       Access: Public
 //  Description: This is called by P3DPackage when it migrates from
 //               this host to its final alt_host, after downloading
@@ -546,20 +664,21 @@ forget_package(P3DPackage *package, const string &alt_host) {
 //               true URL for its target alt_host.
 ////////////////////////////////////////////////////////////////////
 void P3DHost::
-migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host) {
+migrate_package_host(P3DPackage *package, const string &alt_host, P3DHost *new_host) {
   assert(new_host != this);
   assert(new_host == get_alt_host(alt_host));
 
   string key = package->get_package_name() + "_" + package->get_package_version();
 
-  PackageMap &package_map = _packages[alt_host];
-  PackageMap::iterator pi = package_map.find(key);
-  assert(pi != package_map.end());
-  package_map.erase(pi);
+  PlatformPackages &ppackages = _packages[alt_host][key];
+
+  PlatformPackages::iterator ppi = find(ppackages.begin(), ppackages.end(), package);
 
-  PackageMap &new_package_map = new_host->_packages[""];
-  bool inserted = new_package_map.insert(PackageMap::value_type(key, package)).second;
-  assert(inserted);
+  assert(ppi != ppackages.end());
+  ppackages.erase(ppi);
+
+  PlatformPackages &new_ppackages = new_host->_packages[""][key];
+  new_ppackages.push_back(package);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -635,8 +754,12 @@ uninstall() {
     PackageMap &package_map = (*mi).second;
     PackageMap::iterator pi;
     for (pi = package_map.begin(); pi != package_map.end(); ++pi) {
-      P3DPackage *package = (*pi).second;
-      package->uninstall();
+      PlatformPackages &ppackages = (*pi).second;
+      PlatformPackages::iterator ppi;
+      for (ppi = ppackages.begin(); ppi != ppackages.end(); ++ppi) {
+        P3DPackage *package = (*ppi);
+        package->uninstall();
+      }
     }
   }
 

+ 10 - 4
direct/src/plugin/p3dHost.h

@@ -54,17 +54,22 @@ public:
 
   P3DPackage *get_package(const string &package_name, 
                           const string &package_version,
+                          const string &package_platform,
                           const string &package_seq,
                           const string &alt_host = "");
+  bool choose_suitable_platform(string &selected_platform,
+                                const string &package_name,
+                                const string &package_version,
+                                const string &package_platform);
   bool get_package_desc_file(FileSpec &desc_file, 
-                             string &package_platform,
                              string &package_seq,
                              bool &package_solo,
                              const string &package_name,
-                             const string &package_version);
+                             const string &package_version,
+                             const string &package_platform);
 
   void forget_package(P3DPackage *package, const string &alt_host = "");
-  void migrate_package(P3DPackage *package, const string &alt_host, P3DHost *new_host);
+  void migrate_package_host(P3DPackage *package, const string &alt_host, P3DHost *new_host);
 
   void choose_random_mirrors(vector<string> &result, int num_mirrors);
   void add_mirror(string mirror_url);
@@ -97,7 +102,8 @@ private:
   typedef map<string, string> AltHosts;
   AltHosts _alt_hosts;
 
-  typedef map<string, P3DPackage *> PackageMap;
+  typedef vector<P3DPackage *> PlatformPackages;
+  typedef map<string, PlatformPackages> PackageMap;
   typedef map<string, PackageMap> Packages;
   Packages _packages;
   typedef vector<P3DPackage *> FailedPackages;

+ 19 - 0
direct/src/plugin/p3dInstance.I

@@ -60,6 +60,25 @@ get_session_key() const {
   return _session_key;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::get_session_platform
+//       Access: Public
+//  Description: Returns the platform of this particular session.
+//               Before the panda3d package has been seen, this is the
+//               empty string; once we have downloaded the info file
+//               for the panda3d package, it is filled in with
+//               whatever platform is provided (that we're also
+//               runtime-compatible with).
+//
+//               Presumably all of the platform-specific packages that
+//               are downloaded subsequently must be of the exact same
+//               platform.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DInstance::
+get_session_platform() const {
+  return _session_platform;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::get_session
 //       Access: Public

+ 91 - 23
direct/src/plugin/p3dInstance.cxx

@@ -146,7 +146,7 @@ P3DInstance(P3D_request_ready_func *func,
   _failed = false;
   _session = NULL;
   _auth_session = NULL;
-  _panda3d = NULL;
+  _panda3d_package = NULL;
   _splash_window = NULL;
   _instance_window_opened = false;
   _instance_window_attached = false;
@@ -241,7 +241,7 @@ P3DInstance(P3D_request_ready_func *func,
   // put up a splash image (for instance, the above IT_download image)
   // while we download the real contents.
   P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-  _image_package = host->get_package("images", "", "");
+  _image_package = host->get_package("images", "", "", "");
   if (_image_package != NULL) {
     _image_package->add_instance(this);
   }
@@ -774,7 +774,7 @@ get_request() {
         P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
         P3DHost *host = inst_mgr->get_host(host_url);
         if (package_name != NULL) {
-          P3DPackage *package = host->get_package(package_name, package_version, "");
+          P3DPackage *package = host->get_package(package_name, package_version, _session_platform, "");
           host->forget_package(package);
         } else {
           // If a NULL package name is given, forget the whole host.
@@ -1066,8 +1066,9 @@ add_package(const string &name, const string &version, const string &seq,
     // get its additional host information.
     get_host_info(host);
   }
-  
-  P3DPackage *package = host->get_package(name, version, seq, alt_host);
+
+  P3DPackage *package = host->get_package(name, version, _session_platform,
+                                          seq, alt_host);
   add_package(package);
 }
     
@@ -1087,7 +1088,7 @@ add_package(P3DPackage *package) {
   }
 
   if (package->get_package_name() == "panda3d") {
-    _panda3d = package;
+    _panda3d_package = package;
   }
 
   _packages.push_back(package);
@@ -1125,6 +1126,9 @@ remove_package(P3DPackage *package) {
   if (package == _p3dcert_package) {
     _p3dcert_package = NULL;
   }
+  if (package == _panda3d_package) {
+    _panda3d_package = NULL;
+  }
 
   set_failed();
 }
@@ -1890,7 +1894,7 @@ check_p3d_signature() {
     // We have to go download this package.
     P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
     P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-    _certlist_package = host->get_package("certlist", "", "");
+    _certlist_package = host->get_package("certlist", "", "", "");
     if (_certlist_package != NULL) {
       _certlist_package->add_instance(this);
     }
@@ -1931,7 +1935,7 @@ mark_p3d_untrusted() {
     // We have to go download this package.
     P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
     P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-    _p3dcert_package = host->get_package("p3dcert", "", "");
+    _p3dcert_package = host->get_package("p3dcert", "", "", "");
     if (_p3dcert_package != NULL) {
       _p3dcert_package->add_instance(this);
     }
@@ -2009,20 +2013,10 @@ mark_p3d_trusted() {
   _main_object->set_bool_property("trusted", true);
   send_notify("onauth");
 
-  // Now that we're all set up, start downloading the required
+  // Now that we're all set up, grab the panda3d package.  We need to
+  // examine this before we can start to download the remaining
   // packages.
-  add_packages();
-
-  // Until we've done all of the above processing, we haven't fully
-  // committed to setting the trusted flag.  (Setting this flag down
-  // here instead of a few lines above avoids starting the instance in
-  // add_packages(), before we've had a chance to finish processing
-  // this method.)
-  _p3d_trusted = true;
-
-  if (get_packages_ready()) {
-    mark_download_complete();
-  }
+  add_panda3d_package();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2132,6 +2126,48 @@ scan_app_desc_file(TiXmlDocument *doc) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstance::add_panda3d_package
+//       Access: Private
+//  Description: Adds the "panda3d" package only.  This package must
+//               be downloaded first, and its desc file examined,
+//               before we can begin downloading the other packages.
+////////////////////////////////////////////////////////////////////
+void P3DInstance::
+add_panda3d_package() {
+  assert(!_packages_specified);
+  assert(_panda3d_package == NULL);
+  if (_xpackage == NULL) {
+    return;
+  }
+
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+
+  TiXmlElement *xrequires = _xpackage->FirstChildElement("requires");
+  while (xrequires != NULL) {
+    const char *name = xrequires->Attribute("name");
+    const char *host_url = xrequires->Attribute("host");
+    if (name != NULL && host_url != NULL && strcmp(name, "panda3d") == 0) {
+      const char *version = xrequires->Attribute("version");
+      if (version == NULL) {
+        version = "";
+      }
+      const char *seq = xrequires->Attribute("seq");
+      if (seq == NULL) {
+        seq = "";
+      }
+      P3DHost *host = inst_mgr->get_host(host_url);
+      add_package(name, version, seq, host);
+      return;
+    }
+
+    xrequires = xrequires->NextSiblingElement("requires");
+  }
+
+  nout << "No panda3d package found in " << _fparams.get_p3d_filename() << "\n";
+  set_failed();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstance::add_packages
 //       Access: Private
@@ -2171,6 +2207,16 @@ add_packages() {
   _packages_specified = true;
 
   consider_start_download();
+
+  // Now that we've scanned the p3d file, and prepared the list of
+  // packages, it's safe to set the trusted flag.
+  _p3d_trusted = true;
+
+  // If the packages are already downloaded, start the instance
+  // rolling.
+  if (get_packages_ready()) {
+    mark_download_complete();
+  }
 }
 
 
@@ -2689,8 +2735,10 @@ make_splash_window() {
     // Don't know where to put it yet.
     return;
   }
-  if (_wparams.get_window_type() == P3D_WT_hidden) {
-    // We're hidden, and so is the splash window.
+  if (_wparams.get_window_type() == P3D_WT_hidden && !is_failed()) {
+    // We're hidden, and so is the splash window.  (But if we've got a
+    // failure case to report, we don't care and create the splash
+    // window anyway.)
     return;
   }
 
@@ -2901,6 +2949,26 @@ report_package_info_ready(P3DPackage *package) {
     return;
   }
 
+  if (package == _panda3d_package && !_packages_specified) {
+    // Another special case.  Once the special panda3d package is
+    // ready to download (and we know what platform it belongs to), we
+    // can begin to download the remaining required packages.
+    string package_platform = package->get_package_platform();
+    if (!package_platform.empty() && _session_platform.empty()) {
+      // From now on, all platform-specific files downloaded by this
+      // session will be for this platform.
+      _session_platform = package_platform;
+    }
+    if (_session_platform != package_platform) {
+      nout << "Error: session is " << _session_platform
+           << ", but we somehow got panda3d for " << package_platform << "\n";
+      set_failed();
+      return;
+    }
+
+    add_packages();
+  }
+
   // Now that the package's info is ready, we know its set of required
   // packages, and we can add these to the list.
   P3DPackage::Requires::const_iterator ri;

+ 4 - 1
direct/src/plugin/p3dInstance.h

@@ -88,6 +88,7 @@ public:
   inline int get_instance_id() const;
   inline const string &get_session_key() const;
   const string &get_log_pathname() const;
+  inline const string &get_session_platform() const;
 
   inline P3DSession *get_session() const;
 
@@ -176,6 +177,7 @@ private:
   void mark_p3d_untrusted();
   void mark_p3d_trusted();
   void scan_app_desc_file(TiXmlDocument *doc);
+  void add_panda3d_package();
   void add_packages();
   string find_alt_host_url(const string &host_url, const string &alt_host);
   void get_host_info(P3DHost *host);
@@ -286,6 +288,7 @@ private:
   int _instance_id;
   string _session_key;
   string _log_basename;
+  string _session_platform;
   string _prc_name;
   string _start_dir;
   bool _hidden;
@@ -356,7 +359,7 @@ private:
 
   // We keep the _panda3d pointer separately because it's so
   // important, but it's in the above vector also.
-  P3DPackage *_panda3d;  
+  P3DPackage *_panda3d_package;
 
   typedef map<int, P3DDownload *> Downloads;
   Downloads _downloads;

+ 32 - 0
direct/src/plugin/p3dInstanceManager.I

@@ -200,6 +200,38 @@ get_console_environment() const {
   return _console_environment;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_num_supported_platforms
+//       Access: Public
+//  Description: Returns the number of different supported platforms
+//               available in get_supported_platform().
+////////////////////////////////////////////////////////////////////
+inline int P3DInstanceManager::
+get_num_supported_platforms() const {
+  return (int)_supported_platforms.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_supported_platform
+//       Access: Public
+//  Description: Returns the nth supported platform, where 0 <= n <
+//               get_num_supported_platforms().
+//
+//               A given runtime environment may support multiple
+//               different platforms, e.g. win32 or win64, with the
+//               restriction that all platform-specific packages
+//               (beginning from panda3d), must be the same platform.
+//
+//               This function enumerates the different platforms that
+//               the current runtime environment will support, in
+//               order of preference--preferred platforms appear first
+//               in the list.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DInstanceManager::
+get_supported_platform(int n) const {
+  return _supported_platforms.at(n);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_plugin_major_version
 //       Access: Public

+ 41 - 0
direct/src/plugin/p3dInstanceManager.cxx

@@ -38,6 +38,7 @@
 #include <shlobj.h>
 #include <io.h>      // chmod()
 #include <direct.h>  // rmdir()
+#include <windows.h> // GetModuleHandle() etc.
 #else
 #include <sys/stat.h>
 #include <signal.h>
@@ -211,9 +212,32 @@ initialize(int api_version, const string &contents_filename,
   }
 
   if (_platform.empty()) {
+    // If the platform is compiled in (as opposed to passed in by the
+    // caller), we might in fact support multiple platforms.
     _platform = DTOOL_PLATFORM;
+    if (_platform == "win64") {
+      _supported_platforms.push_back("win64");
+      _supported_platforms.push_back("win32");
+
+    } else if (_platform == "win32") {
+      // This is a WIN32 process, but determine if the underlying OS
+      // actually supports WIN64.
+      if (supports_win64()) {
+        _supported_platforms.push_back("win64");
+      }
+      _supported_platforms.push_back("win32");
+    }
+
+    // TODO: OSX, Linux multiplatform support.  Just add the
+    // appropriate platform strings to _supported_platforms.
   }
 
+  if (_supported_platforms.empty()) {
+    // We always support at least the specific platform on which we're
+    // running.
+    _supported_platforms.push_back(_platform);
+  }
+      
 #ifdef P3D_PLUGIN_LOG_DIRECTORY
   if (_log_directory.empty()) {
     _log_directory = P3D_PLUGIN_LOG_DIRECTORY;
@@ -1520,3 +1544,20 @@ nt_thread_run() {
   _notify_ready.release();
 }
 
+#ifdef _WIN32
+bool P3DInstanceManager::
+supports_win64() {
+  BOOL is_win64 = false;
+
+  typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+  LPFN_ISWOW64PROCESS _IsWow64Process;
+  _IsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
+  
+  if (_IsWow64Process != NULL) {
+    if (!_IsWow64Process(GetCurrentProcess(), &is_win64)) {
+      is_win64 = false;
+    }
+  }
+  return (is_win64 != 0);
+}
+#endif  // _WIN32

+ 10 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -76,6 +76,9 @@ public:
   inline bool get_trusted_environment() const;
   inline bool get_console_environment() const;
 
+  inline int get_num_supported_platforms() const;
+  inline const string &get_supported_platform(int n) const;
+
   void set_plugin_version(int major, int minor, int sequence,
                           bool official, const string &distributor,
                           const string &coreapi_host_url,
@@ -159,6 +162,10 @@ private:
   THREAD_CALLBACK_DECLARATION(P3DInstanceManager, nt_thread_run);
   void nt_thread_run();
 
+#ifdef _WIN32
+  static bool supports_win64();
+#endif  // _WIN32
+
 private:
   bool _is_initialized;
   bool _created_runtime_environment;
@@ -185,6 +192,9 @@ private:
   string _coreapi_set_ver;
   string _super_mirror_url;
 
+  typedef vector<string> SupportedPlatforms;
+  SupportedPlatforms _supported_platforms;
+
   P3D_object *_undefined_object;
   P3D_object *_none_object;
   P3D_object *_true_object;

+ 10 - 0
direct/src/plugin/p3dPackage.I

@@ -108,6 +108,16 @@ get_package_version() const {
   return _package_version;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::get_package_platform
+//       Access: Public
+//  Description: Returns the platform string of this package.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DPackage::
+get_package_platform() const {
+  return _package_platform;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::get_package_display_name
 //       Access: Public

+ 28 - 7
direct/src/plugin/p3dPackage.cxx

@@ -44,10 +44,12 @@ const double P3DPackage::_patch_factor = 0.01;
 ////////////////////////////////////////////////////////////////////
 P3DPackage::
 P3DPackage(P3DHost *host, const string &package_name,
-           const string &package_version, const string &alt_host) :
+           const string &package_version, const string &package_platform,
+           const string &alt_host) :
   _host(host),
   _package_name(package_name),
   _package_version(package_version),
+  _package_platform(package_platform),
   _alt_host(alt_host)
 {
   _package_fullname = _package_name;
@@ -611,7 +613,7 @@ host_got_contents_file() {
     nout << "Migrating " << get_package_name() << " to alt_host " 
          << _alt_host << ": " << new_host->get_host_url() << "\n";
     if (new_host != _host) {
-      _host->migrate_package(this, _alt_host, new_host);
+      _host->migrate_package_host(this, _alt_host, new_host);
       _host = new_host;
     }
 
@@ -632,11 +634,30 @@ host_got_contents_file() {
   // instance, reloading it).
   _host_contents_iseq = _host->get_contents_iseq();
 
-  // Now that we have a valid host, we can define the _package_dir.
+  // Now adjust the platform based on the available platforms
+  // provided.
+  assert(_alt_host.empty());
+  string new_platform;
+  if (_host->choose_suitable_platform(new_platform, _package_name, _package_version, _package_platform)) {
+    if (new_platform != _package_platform) {
+      nout << "Migrating " << get_package_name() << " from platform \""
+           << _package_platform << "\" to platform \"" 
+           << new_platform << "\"\n";
+      _package_platform = new_platform;
+    }
+  } else {
+    nout << "Couldn't find a platform for " << get_package_name() << ".\n";
+  }
+
+  // Now that we have a valid host and platform, we can define the
+  // _package_dir.
   _package_dir = _host->get_host_dir() + string("/") + _package_name;
   if (!_package_version.empty()) {
     _package_dir += string("/") + _package_version;
   }
+  if (!_package_platform.empty()) {
+    _package_dir += string("/") + _package_platform;
+  }
 
   // Ensure the package directory exists; create it if it does not.
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
@@ -661,11 +682,11 @@ download_desc_file() {
   // exists, and is consistent with the server contents file, we don't
   // need to re-download it.
   string package_seq;
-  if (!_host->get_package_desc_file(_desc_file, _package_platform, 
-                                    package_seq, _package_solo,
-                                    _package_name, _package_version)) {
+  if (!_host->get_package_desc_file(_desc_file, package_seq, _package_solo,
+                                    _package_name, _package_version,
+                                    _package_platform)) {
     nout << "Couldn't find package " << _package_fullname
-         << " in contents file.\n";
+         << "/" << _package_platform << " in contents file.\n";
     redownload_contents_file(NULL);
     return;
   }

+ 2 - 0
direct/src/plugin/p3dPackage.h

@@ -44,6 +44,7 @@ private:
   P3DPackage(P3DHost *host,
              const string &package_name, 
              const string &package_version,
+             const string &package_platform,
              const string &alt_host);
   ~P3DPackage();
 
@@ -58,6 +59,7 @@ public:
   inline const string &get_package_dir() const;
   inline const string &get_package_name() const;
   inline const string &get_package_version() const;
+  inline const string &get_package_platform() const;
   inline const string &get_package_display_name() const;
   string get_formatted_name() const;
   inline const TiXmlElement *get_xconfig() const;

+ 6 - 6
direct/src/plugin/p3dSession.cxx

@@ -697,7 +697,7 @@ start_p3dpython(P3DInstance *inst) {
     return;
   }
 
-  if (inst->_panda3d == NULL) {
+  if (inst->_panda3d_package == NULL) {
     nout << "Couldn't start Python: no panda3d dependency.\n";
     set_failed();
     return;
@@ -705,7 +705,7 @@ start_p3dpython(P3DInstance *inst) {
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
-  _python_root_dir = inst->_panda3d->get_package_dir();
+  _python_root_dir = inst->_panda3d_package->get_package_dir();
   replace_slashes(_python_root_dir);
 
   // If we're not to be preserving the user's current directory, then
@@ -823,10 +823,10 @@ start_p3dpython(P3DInstance *inst) {
     // Allow package to override the name of the p3dpython executables.
     const char *p3dpython_name_xconfig = NULL; 
     const char *p3dpythonw_name_xconfig = NULL;
-    const TiXmlElement *panda3d_xconfig = inst->_panda3d->get_xconfig();
+    const TiXmlElement *panda3d_xconfig = inst->_panda3d_package->get_xconfig();
     if (panda3d_xconfig != NULL) {
-        p3dpython_name_xconfig = panda3d_xconfig->Attribute("p3dpython_name");
-        p3dpythonw_name_xconfig = panda3d_xconfig->Attribute("p3dpythonw_name");
+      p3dpython_name_xconfig = panda3d_xconfig->Attribute("p3dpython_name");
+      p3dpythonw_name_xconfig = panda3d_xconfig->Attribute("p3dpythonw_name");
     }
 
     string p3dpython_name = "p3dpython";
@@ -1206,7 +1206,7 @@ start_p3dpython(P3DInstance *inst) {
 
   // Get the filename of the Panda3D multifile.  We need to pass this
   // to p3dpython.
-  _mf_filename = inst->_panda3d->get_archive_file_pathname();
+  _mf_filename = inst->_panda3d_package->get_archive_file_pathname();
 
   nout << "Attempting to start python from " << _p3dpython_exe << "\n";
 

+ 3 - 2
direct/src/plugin_standalone/panda3d.cxx

@@ -83,6 +83,7 @@ run_command_line(int argc, char *argv[]) {
 
     case 'p':
       _this_platform = optarg;
+      _coreapi_platform = optarg;
       break;
 
     case 'n':
@@ -506,7 +507,7 @@ read_contents_file(const Filename &contents_filename, bool fresh_download) {
       const char *name = xpackage->Attribute("name");
       if (name != NULL && strcmp(name, "coreapi") == 0) {
         const char *platform = xpackage->Attribute("platform");
-        if (platform != NULL && _this_platform == string(platform)) {
+        if (platform != NULL && _coreapi_platform == string(platform)) {
           _coreapi_dll.load_xml(xpackage);
           const char *set_ver = xpackage->Attribute("set_ver");
           if (set_ver != NULL) {
@@ -524,7 +525,7 @@ read_contents_file(const Filename &contents_filename, bool fresh_download) {
   if (!found_core_package) {
     // Couldn't find the coreapi package description.
     nout << "No coreapi package defined in contents file for "
-         << _this_platform << "\n";
+         << _coreapi_platform << "\n";
     return false;
   }
 

+ 10 - 1
direct/src/plugin_standalone/panda3dBase.cxx

@@ -68,7 +68,11 @@ Panda3DBase(bool console_environment) {
 
   _exit_with_last_instance = true;
   _host_url = PANDA_PACKAGE_HOST_URL;
-  _this_platform = DTOOL_PLATFORM;
+  // Better to leave _this_platform set to the empty string until the
+  // user specifies otherwise; this allows the plugin to select a
+  // suitable platform at runtime.
+  _this_platform = "";
+  _coreapi_platform = DTOOL_PLATFORM;
   _verify_contents = P3D_VC_none;
   _contents_expiration = 0;
 
@@ -235,12 +239,17 @@ handle_request(P3D_request *request) {
 
   case P3D_RT_notify:
     {
+      //cerr << "Notify: " << request->_request._notify._message << "\n";
       if (strcmp(request->_request._notify._message, "ondownloadnext") == 0) {
         // Tell the user we're downloading a package.
         report_downloading_package(request->_instance);
       } else if (strcmp(request->_request._notify._message, "ondownloadcomplete") == 0) {
         // Tell the user we're done downloading.
         report_download_complete(request->_instance);
+      } else if (strcmp(request->_request._notify._message, "onfail") == 0) {
+        // Failure!  What else can we do?
+        cerr << "Failed to execute.\n";
+        exit(1);
       }
     }
     break;

+ 1 - 0
direct/src/plugin_standalone/panda3dBase.h

@@ -77,6 +77,7 @@ protected:
   string _log_dirname;
   string _log_basename;
   string _this_platform;
+  string _coreapi_platform;
   P3D_verify_contents _verify_contents;
   time_t _contents_expiration;
 

+ 9 - 7
direct/src/showutil/FreezeTool.py

@@ -786,13 +786,15 @@ class Freezer:
                 topName = parentName[:-2]
                 newTopName = newParentName[:-2]
                 parentNames = []
-                for dirname in self.getModulePath(topName):
-                    for basename in os.listdir(dirname):
-                        if os.path.exists(os.path.join(dirname, basename, '__init__.py')):
-                            parentName = '%s.%s' % (topName, basename)
-                            newParentName = '%s.%s' % (newTopName, basename)
-                            if self.getModulePath(parentName):
-                                parentNames.append((parentName, newParentName))
+                modulePath = self.getModulePath(topName)
+                if modulePath:
+                    for dirname in modulePath:
+                        for basename in os.listdir(dirname):
+                            if os.path.exists(os.path.join(dirname, basename, '__init__.py')):
+                                parentName = '%s.%s' % (topName, basename)
+                                newParentName = '%s.%s' % (newTopName, basename)
+                                if self.getModulePath(parentName):
+                                    parentNames.append((parentName, newParentName))
 
             for parentName, newParentName in parentNames:
                 modules = self.getModuleStar(parentName)

+ 5 - 4
makepanda/makepanda.py

@@ -4258,7 +4258,9 @@ if (RTDIST or RUNTIME):
       TargetAdd('p3dcert.exe', input='plugin_wstring_encode.obj')
       TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj')
       OPTS=['OPENSSL', 'FLTK', 'WINCOMCTL', 'WINSOCK']
-    else:
+      if (sys.platform=="darwin"): OPTS += ['OPT:2']
+      TargetAdd('p3dcert.exe', opts=OPTS)
+    elif (PkgSkip("WX")==0):
       OPTS.append("WX")
       TargetAdd('plugin_p3dCert.obj', opts=OPTS, input='p3dCert_wx.cxx')
       TargetAdd('p3dcert.exe', input='plugin_mkdir_complete.obj')
@@ -4266,9 +4268,8 @@ if (RTDIST or RUNTIME):
       TargetAdd('p3dcert.exe', input='plugin_p3dCert.obj')
       OPTS=['NOSTRIP', 'OPENSSL', 'WX', 'CARBON', 'WINOLE', 'WINOLEAUT', 'WINUSER', 'ADVAPI', 'WINSHELL', 'WINCOMCTL', 'WINGDI', 'WINCOMDLG']
       if (sys.platform=="darwin"): OPTS.append("GL")
-
-    if (sys.platform=="darwin"): OPTS += ['OPT:2']
-    TargetAdd('p3dcert.exe', opts=OPTS)
+      if (sys.platform=="darwin"): OPTS += ['OPT:2']
+      TargetAdd('p3dcert.exe', opts=OPTS)
 
 #
 # DIRECTORY: direct/src/plugin_npapi/