diff --git a/direct/src/p3d/DeploymentTools.py b/direct/src/p3d/DeploymentTools.py index 069fde3148..c7eeaa9fe0 100644 --- a/direct/src/p3d/DeploymentTools.py +++ b/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) diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index 5efebd1869..182de26659 100644 --- a/direct/src/p3d/Packager.py +++ b/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 diff --git a/direct/src/p3d/packp3d.py b/direct/src/p3d/packp3d.py index 3544022fd6..b26c6d5b22 100755 --- a/direct/src/p3d/packp3d.py +++ b/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': diff --git a/direct/src/plugin/load_plugin.cxx b/direct/src/plugin/load_plugin.cxx index a9276b9e99..8a8e5ef179 100644 --- a/direct/src/plugin/load_plugin.cxx +++ b/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; } diff --git a/direct/src/plugin/load_plugin.h b/direct/src/plugin/load_plugin.h index 985eef7261..f9f89565e5 100644 --- a/direct/src/plugin/load_plugin.h +++ b/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(); diff --git a/direct/src/plugin/p3dAuthSession.cxx b/direct/src/plugin/p3dAuthSession.cxx index 6130119223..103c372f0a 100644 --- a/direct/src/plugin/p3dAuthSession.cxx +++ b/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); diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index d81a271d1e..3f84bb441e 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/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); } diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index caadc083b3..af5b6de16c 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/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 diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 793e6cf36e..fa8c70def2 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/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; diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 78cfcfbdce..b051c01310 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/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; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index e0b9c73f08..3e6189ce4d 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/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); diff --git a/direct/src/plugin/p3d_plugin.cxx b/direct/src/plugin/p3d_plugin.cxx index 8641a72121..241a59d253 100644 --- a/direct/src/plugin/p3d_plugin.cxx +++ b/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; } diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 418d3c1143..f17e26dda3 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/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 diff --git a/direct/src/plugin_activex/PPInstance.cpp b/direct/src/plugin_activex/PPInstance.cpp index a0984a27f6..2151fc63f1 100644 --- a/direct/src/plugin_activex/PPInstance.cpp +++ b/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 { diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 55b9757a04..209204652d 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/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; diff --git a/direct/src/plugin_standalone/p3dEmbed.cxx b/direct/src/plugin_standalone/p3dEmbed.cxx index 4ee1ff31ca..a09c13423b 100644 --- a/direct/src/plugin_standalone/p3dEmbed.cxx +++ b/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; } diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index ab0219f7cf..fd0d2f44b7 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/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 diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h index 36603b93e6..94efc0c41f 100644 --- a/direct/src/plugin_standalone/panda3d.h +++ b/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(); diff --git a/direct/src/plugin_standalone/panda3dBase.h b/direct/src/plugin_standalone/panda3dBase.h index 0f577f39fe..f53e59b14c 100644 --- a/direct/src/plugin_standalone/panda3dBase.h +++ b/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; diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 2ab17b9ae4..0d711b8057 100644 --- a/direct/src/showbase/ShowBase.py +++ b/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 diff --git a/direct/src/stdpy/file.py b/direct/src/stdpy/file.py index 91cf209b04..25f5b6e1a1 100644 --- a/direct/src/stdpy/file.py +++ b/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) - if not self.__stream: - message = 'Could not open %s for writing' % (filename) - raise IOError, message - writeMode = True - - elif mode == 'a': - self.__stream = _vfs.openAppendFile(filename) - if not self.__stream: - message = 'Could not open %s for writing' % (filename) - raise IOError, message - writeMode = True - - elif mode == 'w+': + + # 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+': + 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 == 'r+': + 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 modeType == 'w': + self.__stream = _vfs.openWriteFile(filename, autoUnwrap, True) + if not self.__stream: + message = 'Could not open %s for writing' % (filename) + raise IOError(message) + writeMode = True - elif mode == 'r': + elif modeType == 'a': + self.__stream = _vfs.openAppendFile(filename) + if not self.__stream: + message = 'Could not open %s for writing' % (filename) + raise IOError(message) + writeMode = True + + 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 diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index d7269f78b1..5adfb022ac 100755 --- a/makepanda/makepanda.py +++ b/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" diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index aa3207b806..e5913a1c84 100644 --- a/makepanda/makepandacore.py +++ b/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() diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index fa17aa31da..b804613d9e 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/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; diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 0ee3a85847..37bdce45c9 100644 --- a/panda/src/gobj/texture.cxx +++ b/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: diff --git a/panda/src/linmath/lorientation_src.h b/panda/src/linmath/lorientation_src.h index 350922667f..7c4e33d0a7 100644 --- a/panda/src/linmath/lorientation_src.h +++ b/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; diff --git a/panda/src/linmath/lquaternion_src.h b/panda/src/linmath/lquaternion_src.h index 730c39e637..22b3f0bffe 100644 --- a/panda/src/linmath/lquaternion_src.h +++ b/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) ©); - INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE, const FLOATNAME(LVecBase3) ©); - INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE, FLOATTYPE, FLOATTYPE, FLOATTYPE); + INLINE_LINMATH FLOATNAME(LQuaternion)(FLOATTYPE r, const FLOATNAME(LVecBase3) ©); + 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; diff --git a/panda/src/linmath/lrotation_src.h b/panda/src/linmath/lrotation_src.h index f71a53a3e5..374a0e17a1 100644 --- a/panda/src/linmath/lrotation_src.h +++ b/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) ©); - 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; diff --git a/panda/src/rocket/rocketInputHandler.cxx b/panda/src/rocket/rocketInputHandler.cxx index c0a4e22464..b734e59bef 100644 --- a/panda/src/rocket/rocketInputHandler.cxx +++ b/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(); }