Преглед на файлове

Merge branch 'release/1.9.x'

rdb преди 10 години
родител
ревизия
d569e2ab6f

+ 65 - 13
direct/src/p3d/DeploymentTools.py

@@ -444,6 +444,7 @@ class Installer:
     notify = directNotify.newCategory("Installer")
 
     def __init__(self, p3dfile, shortname, fullname, version, tokens = {}):
+        self.p3dFilename = p3dfile
         if not shortname:
             shortname = p3dfile.getBasenameWoExtension()
         self.shortname = shortname
@@ -477,22 +478,16 @@ class Installer:
         if not self.authoremail and ' ' not in uname:
             self.authoremail = "%s@%s" % (uname, socket.gethostname())
 
-        self.standalone = Standalone(p3dfile, tokens)
-        self.tempDir = Filename.temporary("", self.shortname, "") + "/"
-        self.tempDir.makeDir()
-        self.__tempRoots = {}
-
         # Load the p3d file to read out the required packages
         mf = Multifile()
-        if not mf.openRead(p3dfile):
+        if not mf.openRead(self.p3dFilename):
             Installer.notify.error("Not a Panda3D application: %s" % (p3dfile))
             return
 
         # Now load the p3dInfo file.
-        self.hostUrl = PandaSystem.getPackageHostUrl()
-        if not self.hostUrl:
-            self.hostUrl = self.standalone.host.hostUrl
+        self.hostUrl = None
         self.requires = []
+        self.extracts = []
         i = mf.findSubfile('p3d_info.xml')
         if i >= 0:
             stream = mf.openReadSubfile(i)
@@ -511,14 +506,54 @@ class Installer:
                         p3dRequires.Attribute('host')))
                     p3dRequires = p3dRequires.NextSiblingElement('requires')
 
+                p3dExtract = p3dPackage.FirstChildElement('extract')
+                while p3dExtract:
+                    filename = p3dExtract.Attribute('filename')
+                    self.extracts.append(filename)
+                    p3dExtract = p3dExtract.NextSiblingElement('extract')
+
                 if not self.fullname:
                     p3dConfig = p3dPackage.FirstChildElement('config')
                     if p3dConfig:
                         self.fullname = p3dConfig.Attribute('display_name')
+        else:
+            Installer.notify.warning("No p3d_info.xml was found in .p3d archive.")
+
+        mf.close()
+
+        if not self.hostUrl:
+            self.hostUrl = PandaSystem.getPackageHostUrl()
+            if not self.hostUrl:
+                self.hostUrl = self.standalone.host.hostUrl
+            Installer.notify.warning("No host URL was specified by .p3d archive.  Falling back to %s" % (self.hostUrl))
 
         if not self.fullname:
             self.fullname = self.shortname
 
+        self.tempDir = Filename.temporary("", self.shortname, "") + "/"
+        self.tempDir.makeDir()
+        self.__tempRoots = {}
+
+        if self.extracts:
+            # Copy .p3d to a temporary file so we can remove the extracts.
+            p3dfile = Filename(self.tempDir, self.p3dFilename.getBasename())
+            shutil.copyfile(self.p3dFilename.toOsSpecific(), p3dfile.toOsSpecific())
+            mf = Multifile()
+            if not mf.openReadWrite(p3dfile):
+                Installer.notify.error("Failure to open %s for writing." % (p3dfile))
+
+            # We don't really need this silly thing when embedding, anyway.
+            mf.setHeaderPrefix("")
+
+            for fn in self.extracts:
+                if not mf.removeSubfile(fn):
+                    Installer.notify.error("Failure to remove %s from multifile." % (p3dfile))
+
+            mf.repack()
+            mf.close()
+
+        self.standalone = Standalone(p3dfile, tokens)
+
     def __del__(self):
         try:
             appRunner.rmtree(self.tempDir)
@@ -533,6 +568,22 @@ class Installer:
         if not self.includeRequires:
             return
 
+        # Write out the extracts from the original .p3d.
+        if self.extracts:
+            mf = Multifile()
+            if not mf.openRead(self.p3dFilename):
+                Installer.notify.error("Failed to open .p3d archive: %s" % (filename))
+
+            for filename in self.extracts:
+                i = mf.findSubfile(filename)
+                if i < 0:
+                    Installer.notify.error("Cannot find extract in .p3d archive: %s" % (filename))
+                    continue
+
+                if not mf.extractSubfile(i, Filename(hostDir, filename)):
+                    Installer.notify.error("Failed to extract file from .p3d archive: %s" % (filename))
+            mf.close()
+
         pkgTree = PackageTree(platform, hostDir, self.hostUrl)
         pkgTree.installPackage("images", None, self.standalone.host.hostUrl)
 
@@ -660,7 +711,8 @@ class Installer:
 
         Filename(tempdir, "usr/bin/").makeDir()
         if self.includeRequires:
-            extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower()}
+            extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower(),
+                           "start_dir" : "/usr/lib/" + self.shortname.lower()}
         else:
             extraTokens = {}
         self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform, extraTokens)
@@ -712,7 +764,7 @@ class Installer:
         print >>desktop, "Type=Application"
         desktop.close()
 
-        if self.includeRequires:
+        if self.includeRequires or self.extracts:
             hostDir = Filename(tempdir, "usr/lib/%s/" % self.shortname.lower())
             hostDir.makeDir()
             self.installPackagesInto(hostDir, platform)
@@ -853,7 +905,7 @@ class Installer:
         exefile = Filename(output, "Contents/MacOS/" + self.shortname)
         exefile.makeDir()
         if self.includeRequires:
-            extraTokens = {"host_dir" : "../Resources"}
+            extraTokens = {"host_dir": "../Resources", "start_dir": "../Resources"}
         else:
             extraTokens = {}
         self.standalone.build(exefile, platform, extraTokens)
@@ -1064,7 +1116,7 @@ class Installer:
         exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe")
         exefile.unlink()
         if self.includeRequires:
-            extraTokens = {"host_dir" : "."}
+            extraTokens = {"host_dir": ".", "start_dir": "."}
         else:
             extraTokens = {}
         self.standalone.build(exefile, platform, extraTokens)

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

@@ -1496,6 +1496,10 @@ class Packager:
                     xhost = he.makeXml(packager = self.packager)
                     xpackage.InsertEndChild(xhost)
 
+            self.extracts.sort()
+            for name, xextract in self.extracts:
+                xpackage.InsertEndChild(xextract)
+
             doc.InsertEndChild(xpackage)
 
             # Write the xml file to a temporary file on disk, so we

+ 10 - 0
direct/src/p3d/packp3d.py

@@ -57,6 +57,14 @@ Options:
      instead of -e for files that are uncompressible by their nature
      (e.g. mpg files).  This option may be repeated as necessary.
 
+  -x ext
+     Marks files with the given extensions of needing to be physically
+     extracted to disk before they can be loaded.  This is used for
+     file types that cannot be loaded via the virtual file system,
+     such as .ico files on Windows.
+     This option is currently only implemented when deploying the
+     application with pdeploy.
+
   -p python_lib_dir
      Adds a directory to search for additional Python modules.  You
      can use this to add your system's Python path, to allow packp3d
@@ -134,6 +142,8 @@ def makePackedApp(args):
             packager.binaryExtensions.append(value)
         elif option == '-n':
             packager.uncompressibleExtensions.append(value)
+        elif option == '-x':
+            packager.extractExtensions.append(value)
         elif option == '-p':
             sys.path.append(value)
         elif option == '-c':

+ 17 - 6
direct/src/plugin/load_plugin.cxx

@@ -140,7 +140,7 @@ load_plugin(const string &p3d_plugin_filename,
             const string &log_directory, const string &log_basename,
             bool trusted_environment, bool console_environment,
             const string &root_dir, const string &host_dir,
-            ostream &logfile) {
+            const string &start_dir, ostream &logfile) {
   if (plugin_loaded) {
     return true;
   }
@@ -259,7 +259,7 @@ load_plugin(const string &p3d_plugin_filename,
                    verify_contents, platform,
                    log_directory, log_basename,
                    trusted_environment, console_environment,
-                   root_dir, host_dir, logfile)) {
+                   root_dir, host_dir, start_dir, logfile)) {
     unload_dso();
     return false;
   }
@@ -283,7 +283,7 @@ init_plugin(const string &contents_filename, const string &host_url,
             const string &log_directory, const string &log_basename,
             bool trusted_environment, bool console_environment,
             const string &root_dir, const string &host_dir,
-            ostream &logfile) {
+            const string &start_dir, ostream &logfile) {
 
   // Ensure that all of the function pointers have been found.
   if (P3D_initialize_ptr == NULL ||
@@ -371,15 +371,26 @@ init_plugin(const string &contents_filename, const string &host_url,
     return false;
   }
 
-  if (!P3D_initialize_ptr(P3D_API_VERSION, contents_filename.c_str(),
+  // A bit of extra hand-hacked compatibility for using newer plug-ins
+  // with an older version of the core API.
+  int api_version = P3D_API_VERSION;
+  if (api_version == 17 && start_dir.empty()) {
+    api_version = 16;
+    if (host_dir.empty()) {
+      api_version = 15;
+    }
+  }
+
+  if (!P3D_initialize_ptr(api_version, contents_filename.c_str(),
                           host_url.c_str(), verify_contents, platform.c_str(),
                           log_directory.c_str(), log_basename.c_str(),
                           trusted_environment, console_environment, 
-                          root_dir.c_str(), host_dir.c_str())) {
+                          root_dir.c_str(), host_dir.c_str(),
+                          start_dir.c_str())) {
     // Oops, failure to initialize.
     logfile
       << "Failed to initialize plugin (passed API version " 
-      << P3D_API_VERSION << ")\n";
+      << api_version << ")\n";
     return false;
   }
 

+ 4 - 2
direct/src/plugin/load_plugin.h

@@ -67,13 +67,15 @@ load_plugin(const string &p3d_plugin_filename,
             P3D_verify_contents verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
             bool trusted_environment, bool console_environment,
-            const string &root_dir, const string &host_dir, ostream &logfile);
+            const string &root_dir, const string &host_dir,
+            const string &start_dir, ostream &logfile);
 bool
 init_plugin(const string &contents_filename, const string &host_url, 
             P3D_verify_contents verify_contents, const string &platform,
             const string &log_directory, const string &log_basename,
             bool trusted_environment, bool console_environment,
-            const string &root_dir, const string &host_dir, ostream &logfile);
+            const string &root_dir, const string &host_dir,
+            const string &start_dir, ostream &logfile);
 
 void unload_plugin(ostream &logfile);
 bool is_plugin_loaded();

+ 1 - 1
direct/src/plugin/p3dAuthSession.cxx

@@ -163,7 +163,7 @@ start_p3dcert() {
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
-  _start_dir = inst_mgr->get_root_dir() + "/start";
+  _start_dir = inst_mgr->get_start_dir();
 
   string root_dir = _inst->_p3dcert_package->get_package_dir();
   mkdir_complete(_start_dir, nout);

+ 1 - 1
direct/src/plugin/p3dInstance.cxx

@@ -1564,7 +1564,7 @@ uninstall_packages() {
   if (inst_mgr->get_verify_contents() != P3D_VC_never) {
     string start_dir_suffix = get_start_dir_suffix();
     if (!start_dir_suffix.empty()) {
-      string start_dir = inst_mgr->get_root_dir() + "/start" + start_dir_suffix;
+      string start_dir = inst_mgr->get_start_dir() + start_dir_suffix;
       nout << "Cleaning up start directory " << start_dir << "\n";
       inst_mgr->delete_directory_recursively(start_dir);
     }

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

@@ -111,6 +111,18 @@ get_root_dir() const {
   return _root_dir;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::get_start_dir
+//       Access: Public
+//  Description: Returns the directory that the .p3d file should be
+//               mounted to and run from.  This is usually the
+//               "start" subdirectory of the root_dir.
+////////////////////////////////////////////////////////////////////
+inline const string &P3DInstanceManager::
+get_start_dir() const {
+  return _start_dir;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_platform
 //       Access: Public

+ 14 - 5
direct/src/plugin/p3dInstanceManager.cxx

@@ -201,7 +201,8 @@ initialize(int api_version, const string &contents_filename,
            const string &platform, const string &log_directory,
            const string &log_basename, bool trusted_environment,
            bool console_environment,
-           const string &root_dir, const string &host_dir) {
+           const string &root_dir, const string &host_dir,
+           const string &start_dir) {
   _api_version = api_version;
   _host_url = host_url;
   _verify_contents = verify_contents;
@@ -298,12 +299,18 @@ initialize(int api_version, const string &contents_filename,
   } else {
     _root_dir = root_dir;
   }
-  
+
   _host_dir = host_dir;
 
+  if (start_dir.empty()) {
+    _start_dir = _root_dir + "/start";
+  } else {
+    _start_dir = start_dir;
+  }
+
   // Allow the caller (e.g. panda3d.exe) to specify a log directory.
   // Or, allow the developer to compile one in.
-  
+  //
   // Failing that, we write logfiles to Panda3D/log.
   if (_log_directory.empty()) {
     _log_directory = _root_dir + "/log";
@@ -1515,8 +1522,10 @@ create_runtime_environment() {
 
   // Make the certificate directory.
   _certs_dir = _root_dir + "/certs";
-  if (!mkdir_complete(_certs_dir, nout)) {
-    nout << "Couldn't mkdir " << _certs_dir << "\n";
+  if (!get_trusted_environment()) {
+    if (!mkdir_complete(_certs_dir, nout)) {
+      nout << "Couldn't mkdir " << _certs_dir << "\n";
+    }
   }
 
   _created_runtime_environment = true;

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

@@ -59,7 +59,8 @@ public:
                   bool trusted_environment,
                   bool console_environment,
                   const string &root_dir = "",
-                  const string &host_dir = "");
+                  const string &host_dir = "",
+                  const string &start_dir = "");
 
   inline bool is_initialized() const;
   inline void reconsider_runtime_environment();
@@ -69,6 +70,7 @@ public:
   inline int get_api_version() const;
   inline const string &get_host_url() const;
   inline const string &get_root_dir() const;
+  inline const string &get_start_dir() const;
   inline const string &get_platform() const;
   inline const string &get_temp_directory() const;
   inline const string &get_log_directory() const;
@@ -173,6 +175,7 @@ private:
   string _host_url;
   string _root_dir;
   string _host_dir;
+  string _start_dir;
   string _certs_dir;
   P3D_verify_contents _verify_contents;
   string _platform;

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

@@ -717,7 +717,7 @@ start_p3dpython(P3DInstance *inst) {
     _keep_user_env = true;
   }
   if (!_keep_user_env) {
-    _start_dir = inst_mgr->get_root_dir() + "/start" + inst->get_start_dir_suffix();
+    _start_dir = inst_mgr->get_start_dir() + inst->get_start_dir_suffix();
     mkdir_complete(_start_dir, nout);
   }
   replace_slashes(_start_dir);

+ 7 - 2
direct/src/plugin/p3d_plugin.cxx

@@ -39,7 +39,8 @@ P3D_initialize(int api_version, const char *contents_filename,
                const char *platform, const char *log_directory,
                const char *log_basename, bool trusted_environment,
                bool console_environment,
-               const char *root_dir, const char *host_dir) {
+               const char *root_dir, const char *host_dir,
+               const char *start_dir) {
   if (api_version < 10 || api_version > P3D_API_VERSION) {
     // Can't accept an incompatible version.
     return false;
@@ -89,12 +90,16 @@ P3D_initialize(int api_version, const char *contents_filename,
     host_dir = "";
   }
 
+  if (api_version < 17 || start_dir == NULL) {
+    start_dir = "";
+  }
+
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   bool result = inst_mgr->initialize(api_version, contents_filename, host_url,
                                      verify_contents, platform,
                                      log_directory, log_basename,
                                      trusted_environment, console_environment,
-                                     root_dir, host_dir);
+                                     root_dir, host_dir, start_dir);
   RELEASE_LOCK(_api_lock);
   return result;
 }

+ 3 - 2
direct/src/plugin/p3d_plugin.h

@@ -83,7 +83,7 @@ extern "C" {
    (below). This number will be incremented whenever there are changes
    to any of the interface specifications defined in this header
    file. */
-#define P3D_API_VERSION 16
+#define P3D_API_VERSION 17
 
 /************************ GLOBAL FUNCTIONS **************************/
 
@@ -165,7 +165,8 @@ P3D_initialize_func(int api_version, const char *contents_filename,
                     const char *platform,
                     const char *log_directory, const char *log_basename,
                     bool trusted_environment, bool console_environment,
-                    const char *root_dir, const char *host_dir);
+                    const char *root_dir, const char *host_dir,
+                    const char *start_dir);
 
 /* This function should be called to unload the core API.  It will
    release all internally-allocated memory and return the core API to

+ 3 - 3
direct/src/plugin_activex/PPInstance.cpp

@@ -581,12 +581,12 @@ int PPInstance::LoadPlugin( const std::string& dllFilename )
         pathname = override_filename;
       }
 #endif  // P3D_PLUGIN_P3D_PLUGIN
-      
+
       nout << "Attempting to load core API from " << pathname << "\n";
       string contents_filename = m_rootDir + "/contents.xml";
       if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
-                       P3D_VC_normal, "", "", "", false, false, 
-                       m_rootDir, "", nout)) {
+                       P3D_VC_normal, "", "", "", false, false,
+                       m_rootDir, "", "", nout)) {
         nout << "Unable to launch core API in " << pathname << "\n";
         error = 1;
       } else {

+ 2 - 2
direct/src/plugin_npapi/ppInstance.cxx

@@ -1738,8 +1738,8 @@ do_load_plugin() {
   nout << "Attempting to load core API from " << pathname << "\n";
   string contents_filename = _root_dir + "/contents.xml";
   if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
-                   P3D_VC_normal, "", "", "", false, false, 
-                   _root_dir, "", nout)) {
+                   P3D_VC_normal, "", "", "", false, false,
+                   _root_dir, "", "", nout)) {
     nout << "Unable to launch core API in " << pathname << "\n";
     set_failed();
     return;

+ 23 - 6
direct/src/plugin_standalone/p3dEmbed.cxx

@@ -53,7 +53,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
   // the + 1 from the test.
   _read_offset_check = read_offset + (streampos)1;
   if (_read_offset_check == (streampos)0xFF3D3D01) {
-    cerr << "This program is not intended to be run directly.\nIt is used by pdeploy to construct an embedded Panda3D application.\n";
+    cerr << "This program is not intended to be run directly.\nIt is used "
+            "by pdeploy to construct an embedded Panda3D application.\n";
     return 1;
   }
 
@@ -86,22 +87,30 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
   string value;
   string root_dir;
   string host_dir;
+  string start_dir;
+
   while (true) {
     if (curchr == EOF) {
       cerr << "Truncated stream\n";
-      return(1);
+      return 1;
 
     } else if (curchr == 0) {
       // Two null bytes in a row means we've reached the end of the data.
       if (havenull) {
         break;
       }
-      
+
       // This means we haven't seen an '=' character yet.
       if (keyword == "") {
         if (curstr != "") {
           cerr << "Ignoring token '" << curstr << "' without value\n";
         }
+
+      } else if (keyword == "start_dir") {
+        // Don't pass this on as a token, since it has slightly different
+        // semantics when used as an HTML token.
+        start_dir = curstr;
+
       } else {
         value.assign(curstr);
         P3D_token token;
@@ -118,6 +127,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
           _got_win_size = true;
         } else if (keyword == "log_basename") {
           _log_basename = value;
+        } else if (keyword == "log_directory") {
+          _log_dirname = value;
         } else if (keyword == "root_dir") {
           root_dir = value;
         } else if (keyword == "host_dir") {
@@ -168,6 +179,13 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
     _host_dir = host_dir_f.to_os_specific();
   }
 
+  // Make the start directory absolute
+  if (!start_dir.empty()) {
+    Filename start_dir_f(start_dir);
+    start_dir_f.make_absolute(f.get_dirname());
+    _start_dir = start_dir_f.to_os_specific();
+  }
+
   // Initialize the core API by directly assigning all of the function
   // pointers.
   P3D_initialize_ptr = &P3D_initialize;
@@ -229,18 +247,17 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
   // function pointers.  This will also call P3D_initialize().
   if (!init_plugin("", _host_url, _verify_contents, _this_platform, 
                    _log_dirname, _log_basename, true, _console_environment,
-                   _root_dir, _host_dir, cerr)) {
+                   _root_dir, _host_dir, _start_dir, cerr)) {
     cerr << "Unable to launch core API\n";
     return 1;
   }
-  
+
   // Create a plugin instance and run the program
   P3D_instance *inst = create_instance(f, true, argv, argc, read_offset);
   _instances.insert(inst);
   
   run_main_loop();
 
-
   unload_plugin(cerr);
   return 0;
 }

+ 98 - 73
direct/src/plugin_standalone/panda3d.cxx

@@ -690,7 +690,6 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
   }
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::get_core_api
 //       Access: Protected
@@ -700,78 +699,12 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
 ////////////////////////////////////////////////////////////////////
 bool Panda3D::
 get_core_api() {
+  bool is_fresh = false;
   if (!_coreapi_dll.quick_verify(_root_dir)) {
-    // The DLL file needs to be downloaded.  Build up our list of
-    // URL's to attempt to download it from, in reverse order.
-    string url;
-    vector_string core_urls;
-
-    // Our last act of desperation: hit the original host, with a
-    // query uniquifier, to break through any caches.
-    ostringstream strm;
-    strm << _download_url_prefix << _coreapi_dll.get_filename()
-         << "?" << time(NULL);
-    url = strm.str();
-    core_urls.push_back(url);
-
-    // Before we try that, we'll hit the original host, without a
-    // uniquifier.
-    url = _download_url_prefix;
-    url += _coreapi_dll.get_filename();
-    core_urls.push_back(url);
-
-    // And before we try that, we'll try two mirrors, at random.
-    vector_string mirrors;
-    choose_random_mirrors(mirrors, 2);
-    for (vector_string::iterator si = mirrors.begin();
-         si != mirrors.end(); 
-         ++si) {
-      url = (*si) + _coreapi_dll.get_filename();
-      core_urls.push_back(url);
-    }
-
-    // The very first thing we'll try is the super_mirror, if we have
-    // one.
-    if (!_super_mirror_url_prefix.empty()) {
-      url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
-      core_urls.push_back(url);
-    }
-
-    // Now pick URL's off the list, and try them, until we have
-    // success.
-    Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
-    pathname.make_dir();
-    HTTPClient *http = HTTPClient::get_global_ptr();
-
-    bool success = false;
-    while (!core_urls.empty()) {
-      url = core_urls.back();
-      core_urls.pop_back();
-    
-      PT(HTTPChannel) channel = http->get_document(url);
-      if (!channel->download_to_file(pathname)) {
-        cerr << "Unable to download " << url << "\n";
-
-      } else if (!_coreapi_dll.full_verify(_root_dir)) {
-        cerr << "Mismatched download for " << url << "\n";
-
-      } else {
-        // successfully downloaded!
-        success = true;
-        break;
-      }
-    }
-
-    if (!success) {
-      cerr << "Couldn't download core API.\n";
+    if (!download_core_api()) {
       return false;
     }
-
-    // Since we had to download some of it, might as well ask the core
-    // API to check all of it.
-    if (_verify_contents == P3D_VC_none) {
-      _verify_contents = P3D_VC_normal;
-    }
+    is_fresh = true;
   }
 
   // Now we've got the DLL.  Load it.
@@ -795,9 +728,19 @@ get_core_api() {
   if (!load_plugin(pathname, contents_filename.to_os_specific(),
                    _host_url, _verify_contents, _this_platform, _log_dirname,
                    _log_basename, trusted_environment, _console_environment,
-                   _root_dir, "", cerr)) {
-    cerr << "Unable to launch core API in " << pathname << "\n";
-    return false;
+                   _root_dir, _host_dir, _start_dir, cerr)) {
+
+    // If we're not sure this is the latest version, make sure it is
+    // up-to-date, and then try again.
+    if (is_fresh || !download_core_api() ||
+        !load_plugin(pathname, contents_filename.to_os_specific(),
+                     _host_url, _verify_contents, _this_platform, _log_dirname,
+                     _log_basename, trusted_environment, _console_environment,
+                     _root_dir, _host_dir, _start_dir, cerr)) {
+
+      cerr << "Unable to launch core API in " << pathname << "\n";
+      return false;
+    }
   }
 
   // Successfully loaded.
@@ -822,6 +765,88 @@ get_core_api() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Panda3D::download_core_api
+//       Access: Protected
+//  Description: Downloads the latest version of the core API from
+//               the plug-in server.
+////////////////////////////////////////////////////////////////////
+bool Panda3D::
+download_core_api() {
+  // The DLL file needs to be downloaded.  Build up our list of
+  // URL's to attempt to download it from, in reverse order.
+  string url;
+  vector_string core_urls;
+
+  // Our last act of desperation: hit the original host, with a
+  // query uniquifier, to break through any caches.
+  ostringstream strm;
+  strm << _download_url_prefix << _coreapi_dll.get_filename()
+       << "?" << time(NULL);
+  url = strm.str();
+  core_urls.push_back(url);
+
+  // Before we try that, we'll hit the original host, without a
+  // uniquifier.
+  url = _download_url_prefix;
+  url += _coreapi_dll.get_filename();
+  core_urls.push_back(url);
+
+  // And before we try that, we'll try two mirrors, at random.
+  vector_string mirrors;
+  choose_random_mirrors(mirrors, 2);
+  for (vector_string::iterator si = mirrors.begin();
+       si != mirrors.end();
+       ++si) {
+    url = (*si) + _coreapi_dll.get_filename();
+    core_urls.push_back(url);
+  }
+
+  // The very first thing we'll try is the super_mirror, if we have
+  // one.
+  if (!_super_mirror_url_prefix.empty()) {
+    url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
+    core_urls.push_back(url);
+  }
+
+  // Now pick URL's off the list, and try them, until we have
+  // success.
+  Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
+  pathname.make_dir();
+  HTTPClient *http = HTTPClient::get_global_ptr();
+
+  bool success = false;
+  while (!core_urls.empty()) {
+    url = core_urls.back();
+    core_urls.pop_back();
+
+    PT(HTTPChannel) channel = http->get_document(url);
+    if (!channel->download_to_file(pathname)) {
+      cerr << "Unable to download " << url << "\n";
+
+    } else if (!_coreapi_dll.full_verify(_root_dir)) {
+      cerr << "Mismatched download for " << url << "\n";
+
+    } else {
+      // successfully downloaded!
+      success = true;
+      break;
+    }
+  }
+
+  if (!success) {
+    cerr << "Couldn't download core API.\n";
+    return false;
+  }
+
+  // Since we had to download some of it, might as well ask the core
+  // API to check all of it.
+  if (_verify_contents == P3D_VC_none) {
+    _verify_contents = P3D_VC_normal;
+  }
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::usage
 //       Access: Protected

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

@@ -48,6 +48,7 @@ protected:
   void add_mirror(string mirror_url);
   void choose_random_mirrors(vector_string &result, int num_mirrors);
   bool get_core_api();
+  bool download_core_api();
 
   void usage();
 

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

@@ -74,6 +74,7 @@ protected:
   string _host_url;
   string _root_dir;
   string _host_dir;
+  string _start_dir;
   string _log_dirname;
   string _log_basename;
   string _this_platform;

+ 2 - 0
direct/src/showbase/ShowBase.py

@@ -9,6 +9,8 @@ __all__ = ['ShowBase', 'WindowControls']
 
 from panda3d.core import *
 from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gui
+from panda3d.direct import storeAccessibilityShortcutKeys, allowAccessibilityShortcutKeys
+
 
 # This needs to be available early for DirectGUI imports
 import __builtin__ as builtins

+ 47 - 23
direct/src/stdpy/file.py

@@ -11,6 +11,7 @@ __all__ = [
     ]
 
 from panda3d import core
+import sys
 import types
 
 _vfs = core.VirtualFileSystem.getGlobalPtr()
@@ -65,12 +66,27 @@ class file:
             self.filename = filename
             self.name = filename.toOsSpecific()
 
+            if sys.version_info >= (3, 0):
+                # Python 3 is much stricter than Python 2, which lets
+                # unknown flags fall through.
+                for ch in mode:
+                    if not ch in 'rwxabt+U':
+                        raise IOError("invalid mode: " + mode)
+
             binary = False
+            if 'b' in mode and 't' in mode:
+                raise IOError("can't have text and binary mode at once")
+            
             if 'b' in mode:
                 # Strip 'b'.  This means a binary file.
                 i = mode.index('b')
                 mode = mode[:i] + mode[i + 1:]
                 binary = True
+            elif 't' in mode:
+                # Strip 't'.  This means a text file (redundant, yes).
+                i = mode.index('t')
+                mode = mode[:i] + mode[i + 1:]
+                binary = False
 
             if 'U' in mode:
                 # Strip 'U'.  We don't use it; universal-newline support
@@ -83,61 +99,69 @@ class file:
                 mode = 'r'
 
             # Per Python docs, we insist this is true.
-            assert mode[0] in 'rwa'
+            modeType = mode[0]
+            assert modeType in 'rwa'
 
             if binary:
                 filename.setBinary()
             else:
                 filename.setText()
-
-            # Actually open the streams.
-            if mode == 'w':
-                self.__stream = _vfs.openWriteFile(filename, autoUnwrap, True)
+            
+            # Actually open the streams, taking care to 
+            # ignore unknown chars in the mode string.
+            # We already asserted that it starts with a mode
+            # char above, so locate the '+'  
+            if modeType == 'w' and '+' in mode:
+                self.__stream = _vfs.openReadWriteFile(filename, True)
                 if not self.__stream:
                     message = 'Could not open %s for writing' % (filename)
-                    raise IOError, message
+                    raise IOError(message)
+                readMode = True
                 writeMode = True
 
-            elif mode == 'a':
-                self.__stream = _vfs.openAppendFile(filename)
+            elif modeType == 'a' and '+' in mode:
+                self.__stream = _vfs.openReadAppendFile(filename)
                 if not self.__stream:
                     message = 'Could not open %s for writing' % (filename)
-                    raise IOError, message
+                    raise IOError(message)
+                readMode = True
                 writeMode = True
 
-            elif mode == 'w+':
-                self.__stream = _vfs.openReadWriteFile(filename, True)
+            elif modeType == 'r' and '+' in mode:
+                self.__stream = _vfs.openReadWriteFile(filename, False)
                 if not self.__stream:
                     message = 'Could not open %s for writing' % (filename)
-                    raise IOError, message
+                    raise IOError(message)
                 readMode = True
                 writeMode = True
-
-            elif mode == 'a+':
-                self.__stream = _vfs.openReadAppendFile(filename)
+                
+            elif modeType == 'w':
+                self.__stream = _vfs.openWriteFile(filename, autoUnwrap, True)
                 if not self.__stream:
                     message = 'Could not open %s for writing' % (filename)
-                    raise IOError, message
-                readMode = True
+                    raise IOError(message)
                 writeMode = True
 
-            elif mode == 'r+':
-                self.__stream = _vfs.openReadWriteFile(filename, False)
+            elif modeType == 'a':
+                self.__stream = _vfs.openAppendFile(filename)
                 if not self.__stream:
                     message = 'Could not open %s for writing' % (filename)
-                    raise IOError, message
-                readMode = True
+                    raise IOError(message)
                 writeMode = True
 
-            elif mode == 'r':
+            elif modeType == 'r':
                 self.__stream = _vfs.openReadFile(filename, autoUnwrap)
                 if not self.__stream:
                     if not _vfs.exists(filename):
                         message = 'No such file: %s' % (filename)
                     else:
                         message = 'Could not open %s for reading' % (filename)
-                    raise IOError, message
+                    raise IOError(message)
                 readMode = True
+                
+            else:
+                # should not get here unless there's a bug above
+                raise IOError("Unhandled mode flags: " + mode)
 
             self.__needsVfsClose = True
 

+ 2 - 2
makepanda/makepanda.py

@@ -6674,8 +6674,8 @@ def MakeInstallerLinux():
             depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip()
             recommends = ReadFile("targetroot/debian/substvars_rec").replace("shlibs:Depends=", "").strip()
             if PkgSkip("PYTHON")==0:
-                depends += ", " + PYTHONV + ", python-pmw"
-                recommends += ", python-wxversion, python-profiler (>= " + PV + "), python-tk (>= " + PV + ")"
+                depends += ", " + PYTHONV
+                recommends += ", python-wxversion, python-profiler (>= " + PV + "), python-pmw, python-tk (>= " + PV + ")"
             if PkgSkip("NVIDIACG")==0:
                 depends += ", nvidia-cg-toolkit"
 

+ 3 - 0
makepanda/makepandacore.py

@@ -2301,6 +2301,9 @@ def SetupBuildEnvironment(compiler):
         print("Target OS: %s" % GetTarget())
     print("Target arch: %s" % GetTargetArch())
 
+    # Set to English so we can safely parse the result of gcc commands.
+    os.environ["LC_ALL"] = "C"
+
     if compiler == "MSVC":
         # Add the visual studio tools to PATH et al.
         SetupVisualStudioEnviron()

+ 1 - 1
panda/src/display/graphicsStateGuardian.cxx

@@ -1975,7 +1975,7 @@ flush_timer_queries() {
 
       if (_pending_timer_queries[i]->is_answer_ready()) {
         first = count;
-        while (i < count) {
+        while (i < count - 1) {
           if (!_pending_timer_queries[++i]->is_answer_ready()) {
             first = i;
             break;

+ 11 - 5
panda/src/gobj/texture.cxx

@@ -502,11 +502,14 @@ estimate_texture_memory() const {
   case Texture::F_green:
   case Texture::F_blue:
   case Texture::F_luminance:
+  case Texture::F_sluminance:
+    bpp = 1;
+    break;
+
   case Texture::F_luminance_alpha:
   case Texture::F_luminance_alphamask:
-  case Texture::F_sluminance:
   case Texture::F_sluminance_alpha:
-    bpp = 4;
+    bpp = 2;
     break;
 
   case Texture::F_rgba:
@@ -529,13 +532,16 @@ estimate_texture_memory() const {
     break;
 
   case Texture::F_depth_stencil:
+    bpp = 4;
+    break;
+
   case Texture::F_depth_component:
-    bpp = 32;
+    bpp = 2;
     break;
 
   case Texture::F_rgba12:
   case Texture::F_rgb12:
-    bpp = 6;
+    bpp = 8;
     break;
 
   case Texture::F_rgba16:
@@ -554,7 +560,7 @@ estimate_texture_memory() const {
     bpp = 4;
     break;
   case Texture::F_rgb16:
-    bpp = 6;
+    bpp = 8;
     break;
 
   case Texture::F_r32i:

+ 5 - 5
panda/src/linmath/lorientation_src.h

@@ -21,11 +21,11 @@ class FLOATNAME(LRotation);
 class EXPCL_PANDA_LINMATH FLOATNAME(LOrientation) : public FLOATNAME(LQuaternion) {
 PUBLISHED:
   INLINE_LINMATH FLOATNAME(LOrientation)();
-  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LQuaternion)&);
-  INLINE_LINMATH FLOATNAME(LOrientation)(FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE);
-  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LVector3) &, float);
-  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LMatrix3) &);
-  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LMatrix4) &);
+  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LQuaternion) &c);
+  INLINE_LINMATH FLOATNAME(LOrientation)(FLOATTYPE r, FLOATTYPE i, FLOATTYPE j, FLOATTYPE k);
+  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LVector3) &point_at, float twist);
+  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LMatrix3) &m);
+  INLINE_LINMATH FLOATNAME(LOrientation)(const FLOATNAME(LMatrix4) &m);
 
   INLINE_LINMATH FLOATNAME(LOrientation)
   operator * (const FLOATNAME(LRotation) &other) const;

+ 3 - 3
panda/src/linmath/lquaternion_src.h

@@ -20,10 +20,10 @@ class EXPCL_PANDA_LINMATH FLOATNAME(LQuaternion) : public FLOATNAME(LVecBase4) {
 PUBLISHED:
   INLINE_LINMATH FLOATNAME(LQuaternion)();
   INLINE_LINMATH FLOATNAME(LQuaternion)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE, const FLOATNAME(LVecBase3) &copy);
-  INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE);
+  INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE r, const FLOATNAME(LVecBase3) &copy);
+  INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE r, FLOATTYPE i, FLOATTYPE j, FLOATTYPE k);
 
-  static FLOATNAME(LQuaternion) pure_imaginary(const FLOATNAME(LVector3) &);
+  static FLOATNAME(LQuaternion) pure_imaginary(const FLOATNAME(LVector3) &v);
 
   INLINE_LINMATH FLOATNAME(LQuaternion) conjugate() const;
 

+ 6 - 6
panda/src/linmath/lrotation_src.h

@@ -19,13 +19,13 @@
 class EXPCL_PANDA_LINMATH FLOATNAME(LRotation) : public FLOATNAME(LQuaternion) {
 PUBLISHED:
   INLINE_LINMATH FLOATNAME(LRotation)();
-  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LQuaternion) &);
+  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LQuaternion) &c);
   INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LVecBase4) &copy);
-  INLINE_LINMATH FLOATNAME(LRotation)(FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE);
-  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LVector3) &, FLOATTYPE);
-  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LMatrix3) &);
-  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LMatrix4) &);
-  INLINE_LINMATH FLOATNAME(LRotation)(FLOATTYPE, FLOATTYPE, FLOATTYPE);
+  INLINE_LINMATH FLOATNAME(LRotation)(FLOATTYPE r, FLOATTYPE i, FLOATTYPE j, FLOATTYPE k);
+  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LVector3) &axis, FLOATTYPE angle);
+  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LMatrix3) &m);
+  INLINE_LINMATH FLOATNAME(LRotation)(const FLOATNAME(LMatrix4) &m);
+  INLINE_LINMATH FLOATNAME(LRotation)(FLOATTYPE h, FLOATTYPE p, FLOATTYPE r);
 
   INLINE_LINMATH FLOATNAME(LRotation) operator * (FLOATTYPE scalar) const;
   INLINE_LINMATH FLOATNAME(LRotation) operator / (FLOATTYPE scalar) const;

+ 24 - 24
panda/src/rocket/rocketInputHandler.cxx

@@ -302,30 +302,6 @@ void RocketInputHandler::
 update_context(Rocket::Core::Context *context, int xoffs, int yoffs) {
   MutexHolder holder(_lock);
 
-  if (_mouse_xy_changed) {
-    _mouse_xy_changed = false;
-
-    context->ProcessMouseMove(_mouse_xy.get_x() - xoffs,
-                              _mouse_xy.get_y() - yoffs, _modifiers);
-  }
-
-  if (_mouse_buttons.size() > 0) {
-    ButtonActivityMap::const_iterator it;
-    for (it = _mouse_buttons.begin(); it != _mouse_buttons.end(); ++it) {
-      if (it->second) {
-        context->ProcessMouseButtonDown(it->first, _modifiers);
-      } else {
-        context->ProcessMouseButtonUp(it->first, _modifiers);
-      }
-    }
-    _mouse_buttons.clear();
-  }
-
-  if (_wheel_delta != 0) {
-    context->ProcessMouseWheel(_wheel_delta, _modifiers);
-    _wheel_delta = 0;
-  }
-
   if (_keys.size() > 0) {
     ButtonActivityMap::const_iterator it;
     for (it = _keys.begin(); it != _keys.end(); ++it) {
@@ -356,5 +332,29 @@ update_context(Rocket::Core::Context *context, int xoffs, int yoffs) {
     _text_input.clear();
   }
 
+  if (_mouse_xy_changed) {
+    _mouse_xy_changed = false;
+
+    context->ProcessMouseMove(_mouse_xy.get_x() - xoffs,
+                              _mouse_xy.get_y() - yoffs, _modifiers);
+  }
+
+  if (_mouse_buttons.size() > 0) {
+    ButtonActivityMap::const_iterator it;
+    for (it = _mouse_buttons.begin(); it != _mouse_buttons.end(); ++it) {
+      if (it->second) {
+        context->ProcessMouseButtonDown(it->first, _modifiers);
+      } else {
+        context->ProcessMouseButtonUp(it->first, _modifiers);
+      }
+    }
+    _mouse_buttons.clear();
+  }
+
+  if (_wheel_delta != 0) {
+    context->ProcessMouseWheel(_wheel_delta, _modifiers);
+    _wheel_delta = 0;
+  }
+
   context->Update();
 }