Browse Source

Merge branch 'master' into deploy-ng

rdb 7 years ago
parent
commit
a7752da4f1
47 changed files with 1532 additions and 2191 deletions
  1. 0 1
      doc/INSTALL
  2. 122 3
      dtool/src/dtoolutil/globPattern.cxx
  3. 2 0
      dtool/src/dtoolutil/globPattern.h
  4. 0 1
      makepanda/installer.nsi
  5. 964 0
      makepanda/makepackage.py
  6. 34 911
      makepanda/makepanda.py
  7. 0 19
      makepanda/makepanda.vcproj
  8. 1 1
      panda/src/audiotraits/openalAudioSound.cxx
  9. 0 47
      panda/src/awesomium/AwMouseAndKeyboard.cxx
  10. 0 61
      panda/src/awesomium/AwMouseAndKeyboard.h
  11. 0 8
      panda/src/awesomium/ReadMe.txt
  12. 0 194
      panda/src/awesomium/WebBrowserTexture.cxx
  13. 0 77
      panda/src/awesomium/WebBrowserTexture.h
  14. 0 48
      panda/src/awesomium/awWebCore.I
  15. 0 56
      panda/src/awesomium/awWebCore.cxx
  16. 0 94
      panda/src/awesomium/awWebCore.h
  17. 0 82
      panda/src/awesomium/awWebView.I
  18. 0 74
      panda/src/awesomium/awWebView.cxx
  19. 0 131
      panda/src/awesomium/awWebView.h
  20. 0 12
      panda/src/awesomium/awWebViewListener.I
  21. 0 80
      panda/src/awesomium/awWebViewListener.cxx
  22. 0 123
      panda/src/awesomium/awWebViewListener.h
  23. 0 21
      panda/src/awesomium/awesomium_includes.h
  24. 0 51
      panda/src/awesomium/config_awesomium.cxx
  25. 0 26
      panda/src/awesomium/config_awesomium.h
  26. 0 4
      panda/src/awesomium/pandaawesomium_composite1.cxx
  27. 6 3
      panda/src/bullet/bulletVehicle.cxx
  28. 15 0
      panda/src/cocoadisplay/cocoaPandaView.mm
  29. 23 1
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  30. 2 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  31. 20 9
      panda/src/gobj/geomPrimitive.cxx
  32. 44 24
      panda/src/gobj/geomVertexData.cxx
  33. 3 0
      panda/src/gobj/geomVertexData.h
  34. 0 8
      panda/src/pandabase/pandasymbols.h
  35. 9 0
      panda/src/pgraph/billboardEffect.I
  36. 40 5
      panda/src/pgraph/billboardEffect.cxx
  37. 7 2
      panda/src/pgraph/billboardEffect.h
  38. 23 2
      panda/src/pgraph/compassEffect.cxx
  39. 2 0
      panda/src/pgraph/compassEffect.h
  40. 1 0
      panda/src/pgraph/config_pgraph.cxx
  41. 2 2
      panda/src/pgraph/nodePath.I
  42. 70 3
      panda/src/pgraph/nodePath.cxx
  43. 5 2
      panda/src/pgraph/nodePath.h
  44. 2 1
      panda/src/putil/bam.h
  45. 20 0
      panda/src/x11display/x11GraphicsWindow.cxx
  46. 85 0
      tests/dtoolutil/test_globpattern.py
  47. 30 4
      tests/pgraph/test_nodepath.py

+ 0 - 1
doc/INSTALL

@@ -194,7 +194,6 @@ it will show you the available command-line options:
   --use-wx          --no-wx        (enable/disable use of WX)
   --use-fltk        --no-fltk      (enable/disable use of FLTK)
   --use-rocket      --no-rocket    (enable/disable use of ROCKET)
-  --use-awesomium   --no-awesomium (enable/disable use of AWESOMIUM)
   --use-carbon      --no-carbon    (enable/disable use of CARBON)
   --use-cocoa       --no-cocoa     (enable/disable use of COCOA)
   --use-x11         --no-x11       (enable/disable use of X11)

+ 122 - 3
dtool/src/dtoolutil/globPattern.cxx

@@ -12,6 +12,7 @@
  */
 
 #include "globPattern.h"
+#include "string_utils.h"
 #include <ctype.h>
 
 using std::string;
@@ -199,9 +200,7 @@ r_match_files(const Filename &prefix, const string &suffix,
     next_glob = *this;
   }
 
-  vector_string::const_iterator fi;
-  for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
-    const string &local_file = (*fi);
+  for (const string &local_file : dir_files) {
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
       if (matches(local_file)) {
         // We have a match; continue.
@@ -227,6 +226,126 @@ r_match_files(const Filename &prefix, const string &suffix,
   return num_matched;
 }
 
+/**
+ * Treats the GlobPattern as a filename pattern, and returns true if the given
+ * filename matches the pattern.  Unlike matches(), this will not match slash
+ * characters for single asterisk characters, and it will ignore path
+ * components that only contain a dot.
+ */
+bool GlobPattern::
+matches_file(Filename candidate) const {
+  if (_pattern.empty()) {
+    // Special case.
+    return candidate.empty();
+  }
+
+  // Either both must be absolute, or both must be relative.
+  if ((_pattern[0] != '/') != candidate.is_local()) {
+    return false;
+  }
+
+  return r_matches_file(_pattern, candidate);
+}
+
+/**
+ * The recursive implementation of matches_file().
+ */
+bool GlobPattern::
+r_matches_file(const string &pattern, const Filename &candidate) const {
+  // Split off the next bit of pattern.
+  std::string next_pattern;
+  GlobPattern glob;
+  glob.set_case_sensitive(get_case_sensitive());
+  glob.set_nomatch_chars(get_nomatch_chars());
+
+  bool pattern_end;
+  size_t slash = pattern.find('/');
+  if (slash == string::npos) {
+    glob.set_pattern(pattern);
+    pattern_end = true;
+  } else {
+    glob.set_pattern(pattern.substr(0, slash));
+    next_pattern = pattern.substr(slash + 1);
+    pattern_end = false;
+
+    if (slash == 0 || (slash == 1 && pattern[0] == '.')) {
+      // Ignore // and /./ in patterns
+      return r_matches_file(next_pattern, candidate);
+    }
+  }
+
+  // Also split off the next component in the candidate filename.
+  std::string part;
+  Filename next_candidate;
+
+  bool candidate_end;
+  size_t fn_slash = ((const std::string &)candidate).find('/');
+  if (fn_slash == string::npos) {
+    part = candidate;
+    candidate_end = true;
+  } else {
+    part = candidate.substr(0, fn_slash);
+    next_candidate = candidate.substr(fn_slash + 1);
+    candidate_end = false;
+
+    // Ignore // and /./ in filenames.
+    if (fn_slash == 0 || part == ".") {
+      return r_matches_file(pattern, next_candidate);
+    }
+  }
+
+  // Now check if the current part matches the current pattern.
+  bool part_matches;
+  if (glob.get_pattern() == "**") {
+    // This matches any number of parts.
+    if (pattern_end) {
+      // We might as well stop checking here; it matches whatever might come.
+      return true;
+    }
+    // We branch out to three options: either we match nothing, we match this
+    // part only, or we match this part and maybe more.
+    return r_matches_file(next_pattern, candidate)
+        || (!candidate_end && r_matches_file(next_pattern, next_candidate))
+        || (!candidate_end && r_matches_file(pattern, next_candidate));
+  }
+  else if (glob.get_pattern() == "*" && _nomatch_chars.empty()) {
+    // Matches any part (faster version of below)
+    part_matches = true;
+  }
+  else if ((glob.get_pattern() == "." && part.empty())
+        || (glob.get_pattern().empty() && part == ".")) {
+    // So that /path/. matches /path/, and vice versa.
+    part_matches = true;
+  }
+  else if (glob.has_glob_characters()) {
+    part_matches = glob.matches(part);
+  }
+  else if (get_case_sensitive()) {
+    part_matches = (part == glob.get_pattern());
+  }
+  else {
+    part_matches = (cmp_nocase(part, glob.get_pattern()) == 0);
+  }
+
+  if (!part_matches) {
+    // It doesn't match, so we end our search here.
+    return false;
+  }
+
+  if (candidate_end && pattern_end) {
+    // We've reached the end of both candidate and pattern, so it matches.
+    return true;
+  }
+
+  if (pattern_end != candidate_end) {
+    // One of them has ended, but the other hasn't, so it's not a match.
+    return false;
+  }
+
+  // It matches; move on to the next part.
+  return r_matches_file(next_pattern, next_candidate);
+}
+
 /**
  * The recursive implementation of matches().  This returns true if the
  * pattern substring [pi, pend) matches the candidate substring [ci, cend),

+ 2 - 0
dtool/src/dtoolutil/globPattern.h

@@ -52,6 +52,7 @@ PUBLISHED:
   MAKE_PROPERTY(nomatch_chars, get_nomatch_chars, set_nomatch_chars);
 
   INLINE bool matches(const std::string &candidate) const;
+  bool matches_file(Filename candidate) const;
 
   INLINE void output(std::ostream &out) const;
 
@@ -74,6 +75,7 @@ private:
 
   int r_match_files(const Filename &prefix, const std::string &suffix,
                     vector_string &results, const Filename &cwd);
+  bool r_matches_file(const std::string &suffix, const Filename &candidate) const;
 
   std::string _pattern;
   bool _case_sensitive;

+ 0 - 1
makepanda/installer.nsi

@@ -331,7 +331,6 @@ SectionGroup "Python support"
 
         File /nonfatal /r "${BUILT}\panda3d\core${EXT_SUFFIX}"
         File /nonfatal /r "${BUILT}\panda3d\ai${EXT_SUFFIX}"
-        File /nonfatal /r "${BUILT}\panda3d\awesomium${EXT_SUFFIX}"
         File /nonfatal /r "${BUILT}\panda3d\direct${EXT_SUFFIX}"
         File /nonfatal /r "${BUILT}\panda3d\egg${EXT_SUFFIX}"
         File /nonfatal /r "${BUILT}\panda3d\fx${EXT_SUFFIX}"

+ 964 - 0
makepanda/makepackage.py

@@ -0,0 +1,964 @@
+#!/usr/bin/env python
+
+from makepandacore import *
+from installpanda import *
+import sys
+import os
+import shutil
+
+
+INSTALLER_DEB_FILE = """
+Package: panda3dMAJOR
+Version: VERSION
+Section: libdevel
+Priority: optional
+Architecture: ARCH
+Essential: no
+Depends: DEPENDS
+Recommends: RECOMMENDS
+Provides: panda3d, pythonPV-panda3d
+Conflicts: panda3d, pythonPV-panda3d
+Replaces: panda3d, pythonPV-panda3d
+Maintainer: rdb <[email protected]>
+Installed-Size: INSTSIZE
+Description: Panda3D free 3D engine SDK
+ Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
+ Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
+ .
+ This package contains the SDK for development with Panda3D.
+
+"""
+
+RUNTIME_INSTALLER_DEB_FILE = """
+Package: panda3d-runtime
+Version: VERSION
+Section: web
+Priority: optional
+Architecture: ARCH
+Essential: no
+Depends: DEPENDS
+Provides: panda3d-runtime
+Maintainer: rdb <[email protected]>
+Installed-Size: INSTSIZE
+Description: Runtime binary and browser plugin for the Panda3D Game Engine
+ This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
+
+"""
+
+
+# We're not putting "python" in the "Requires" field,
+# since the rpm-based distros don't have a common
+# naming for the Python package.
+INSTALLER_SPEC_FILE = """
+Summary: The Panda3D free 3D engine SDK
+Name: panda3d
+Version: VERSION
+Release: RPMRELEASE
+License: BSD License
+Group: Development/Libraries
+BuildRoot: PANDASOURCE/targetroot
+%description
+Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
+Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
+
+This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files.
+%post
+/sbin/ldconfig
+%postun
+/sbin/ldconfig
+%files
+%defattr(-,root,root)
+/etc/Confauto.prc
+/etc/Config.prc
+/usr/share/panda3d
+/etc/ld.so.conf.d/panda3d.conf
+/usr/%_lib/panda3d
+""" + PYTHON_SITEPACKAGES + """
+/usr/include/panda3d
+"""
+INSTALLER_SPEC_FILE_PVIEW = \
+"""/usr/share/applications/pview.desktop
+/usr/share/mime-info/panda3d.mime
+/usr/share/mime-info/panda3d.keys
+/usr/share/mime/packages/panda3d.xml
+/usr/share/application-registry/panda3d.applications
+"""
+
+RUNTIME_INSTALLER_SPEC_FILE = """
+Summary: Runtime binary and browser plugin for the Panda3D Game Engine
+Name: panda3d-runtime
+Version: VERSION
+Release: RPMRELEASE
+License: BSD License
+Group: Productivity/Graphics/Other
+BuildRoot: PANDASOURCE/targetroot
+%description
+This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
+%files
+%defattr(-,root,root)
+/usr/bin/panda3d
+/usr/%_lib/nppanda3d.so
+/usr/%_lib/mozilla/plugins/nppanda3d.so
+/usr/%_lib/mozilla-firefox/plugins/nppanda3d.so
+/usr/%_lib/xulrunner-addons/plugins/nppanda3d.so
+/usr/share/mime-info/panda3d-runtime.mime
+/usr/share/mime-info/panda3d-runtime.keys
+/usr/share/mime/packages/panda3d-runtime.xml
+/usr/share/application-registry/panda3d-runtime.applications
+/usr/share/applications/*.desktop
+"""
+
+# plist file for Mac OSX
+Info_plist = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleIdentifier</key>
+  <string>{package_id}</string>
+  <key>CFBundleShortVersionString</key>
+  <string>{version}</string>
+  <key>IFPkgFlagRelocatable</key>
+  <false/>
+  <key>IFPkgFlagAuthorizationAction</key>
+  <string>RootAuthorization</string>
+  <key>IFPkgFlagAllowBackRev</key>
+  <true/>
+</dict>
+</plist>
+"""
+
+# FreeBSD pkg-descr
+INSTALLER_PKG_DESCR_FILE = """
+Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
+Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
+
+This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files.
+
+WWW: https://www.panda3d.org/
+"""
+
+# FreeBSD pkg-descr
+RUNTIME_INSTALLER_PKG_DESCR_FILE = """
+Runtime binary and browser plugin for the Panda3D Game Engine
+
+This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
+
+WWW: https://www.panda3d.org/
+"""
+
+# FreeBSD PKG Manifest template file
+INSTALLER_PKG_MANIFEST_FILE = """
+name: NAME
+version: VERSION
+arch: ARCH
+origin: ORIGIN
+comment: "Panda3D free 3D engine SDK"
+www: https://www.panda3d.org
+maintainer: rdb <[email protected]>
+prefix: /usr/local
+flatsize: INSTSIZEMB
+deps: {DEPENDS}
+"""
+
+
+def MakeInstallerNSIS(version, file, title, installdir, runtime=False, compressor="lzma", **kwargs):
+    outputdir = GetOutputDir()
+
+    if os.path.isfile(file):
+        os.remove(file)
+    elif os.path.isdir(file):
+        shutil.rmtree(file)
+
+    if "PYTHONVERSION" in SDK:
+        pyver = SDK["PYTHONVERSION"][6:9]
+    else:
+        pyver = "%d.%d" % (sys.version_info[:2])
+
+    if GetTargetArch() == 'x64':
+        regview = '64'
+    else:
+        regview = '32'
+        if int(pyver[0]) == 3 and int(pyver[2]) >= 5:
+            pyver += '-32'
+
+    if runtime:
+        # Invoke the make_installer script.
+        AddToPathEnv("PATH", outputdir + "\\bin")
+        AddToPathEnv("PATH", outputdir + "\\plugins")
+
+        cmd = sys.executable + " -B -u " + os.path.join("direct", "src", "plugin_installer", "make_installer.py")
+        cmd += " --version %s --regview %s" % (version, regview)
+
+        if GetTargetArch() == 'x64':
+            cmd += " --install \"$PROGRAMFILES64\\Panda3D\" "
+        else:
+            cmd += " --install \"$PROGRAMFILES32\\Panda3D\" "
+
+        oscmd(cmd)
+        shutil.move(os.path.join("direct", "src", "plugin_installer", "p3d-setup.exe"), file)
+        return
+
+    print("Building "+title+" installer at %s" % (file))
+    if compressor != "lzma":
+        print("Note: you are using zlib, which is faster, but lzma gives better compression.")
+    if os.path.exists("nsis-output.exe"):
+        os.remove("nsis-output.exe")
+    WriteFile(outputdir+"/tmp/__init__.py", "")
+
+    nsis_defs = {
+        'COMPRESSOR': compressor,
+        'TITLE'     : title,
+        'INSTALLDIR': installdir,
+        'OUTFILE'   : '..\\' + file,
+        'BUILT'     : '..\\' + outputdir,
+        'SOURCE'    : '..',
+        'PYVER'     : pyver,
+        'REGVIEW'   : regview,
+        'EXT_SUFFIX': GetExtensionSuffix(),
+    }
+
+    if GetHost() == 'windows':
+        cmd = os.path.join(GetThirdpartyBase(), 'win-nsis', 'makensis') + ' /V2'
+        for item in nsis_defs.items():
+            cmd += ' /D%s="%s"' % item
+    else:
+        cmd = 'makensis -V2'
+        for item in nsis_defs.items():
+            cmd += ' -D%s="%s"' % item
+
+    cmd += ' "makepanda\\installer.nsi"'
+    oscmd(cmd)
+
+
+def MakeDebugSymbolArchive(zipname, dirname):
+    outputdir = GetOutputDir()
+
+    import zipfile
+    zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
+
+    for fn in glob.glob(os.path.join(outputdir, 'bin', '*.pdb')):
+        zip.write(fn, dirname + '/bin/' + os.path.basename(fn))
+
+    for fn in glob.glob(os.path.join(outputdir, 'panda3d', '*.pdb')):
+        zip.write(fn, dirname + '/panda3d/' + os.path.basename(fn))
+
+    for fn in glob.glob(os.path.join(outputdir, 'plugins', '*.pdb')):
+        zip.write(fn, dirname + '/plugins/' + os.path.basename(fn))
+
+    for fn in glob.glob(os.path.join(outputdir, 'python', '*.pdb')):
+        zip.write(fn, dirname + '/python/' + os.path.basename(fn))
+
+    for fn in glob.glob(os.path.join(outputdir, 'python', 'DLLs', '*.pdb')):
+        zip.write(fn, dirname + '/python/DLLs/' + os.path.basename(fn))
+
+    zip.close()
+
+
+def MakeInstallerLinux(version, debversion=None, runtime=False, **kwargs):
+    outputdir = GetOutputDir()
+
+    if not runtime and not PkgSkip("PYTHON"):
+        if "PYTHONVERSION" in SDK:
+            PYTHONV = SDK["PYTHONVERSION"].rstrip('dmu')
+        else:
+            PYTHONV = "python%d.%d" % (sys.version_info[:2])
+    else:
+        PYTHONV = "python"
+    PV = PYTHONV.replace("python", "")
+
+    major_version = '.'.join(version.split('.')[:2])
+    if not debversion:
+        debversion = version
+
+    # Clean and set up a directory to install Panda3D into
+    oscmd("rm -rf targetroot data.tar.gz control.tar.gz panda3d.spec")
+    oscmd("mkdir --mode=0755 targetroot")
+
+    dpkg_present = False
+    if os.path.exists("/usr/bin/dpkg-architecture") and os.path.exists("/usr/bin/dpkg-deb"):
+        dpkg_present = True
+    rpmbuild_present = False
+    if os.path.exists("/usr/bin/rpmbuild"):
+        rpmbuild_present = True
+
+    if dpkg_present and rpmbuild_present:
+        Warn("both dpkg and rpmbuild present.")
+
+    if dpkg_present:
+        # Invoke installpanda.py to install it into a temporary dir
+        lib_dir = GetDebLibDir()
+        if runtime:
+            InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=outputdir, libdir=lib_dir)
+        else:
+            InstallPanda(destdir="targetroot", prefix="/usr", outputdir=outputdir, libdir=lib_dir)
+            oscmd("chmod -R 755 targetroot/usr/share/panda3d")
+            oscmd("mkdir -m 0755 -p targetroot/usr/share/man/man1")
+            oscmd("install -m 0644 doc/man/*.1 targetroot/usr/share/man/man1/")
+
+        oscmd("dpkg --print-architecture > "+outputdir+"/tmp/architecture.txt")
+        pkg_arch = ReadFile(outputdir+"/tmp/architecture.txt").strip()
+        if runtime:
+            txt = RUNTIME_INSTALLER_DEB_FILE[1:]
+        else:
+            txt = INSTALLER_DEB_FILE[1:]
+        txt = txt.replace("VERSION", debversion).replace("ARCH", pkg_arch).replace("PV", PV).replace("MAJOR", major_version)
+        txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024))
+        oscmd("mkdir --mode=0755 -p targetroot/DEBIAN")
+        oscmd("cd targetroot && (find usr -type f -exec md5sum {} ;) > DEBIAN/md5sums")
+        if not runtime:
+            oscmd("cd targetroot && (find etc -type f -exec md5sum {} ;) >> DEBIAN/md5sums")
+            WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n")
+        WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n")
+        oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm")
+
+        # Determine the package name and the locations that
+        # dpkg-shlibdeps should look in for executables.
+        pkg_version = debversion
+        if runtime:
+            pkg_name = "panda3d-runtime"
+            lib_pattern = "debian/%s/usr/%s/*.so" % (pkg_name, lib_dir)
+        else:
+            pkg_name = "panda3d" + major_version
+            lib_pattern = "debian/%s/usr/%s/panda3d/*.so*" % (pkg_name, lib_dir)
+        bin_pattern = "debian/%s/usr/bin/*" % (pkg_name)
+
+        # dpkg-shlibdeps looks in the debian/{pkg_name}/DEBIAN/shlibs directory
+        # and also expects a debian/control file, so we create this dummy set-up.
+        oscmd("mkdir targetroot/debian")
+        oscmd("ln -s .. targetroot/debian/" + pkg_name)
+        WriteFile("targetroot/debian/control", "")
+
+        dpkg_shlibdeps = "dpkg-shlibdeps"
+        if GetVerbose():
+            dpkg_shlibdeps += " -v"
+
+        if runtime:
+            # The runtime doesn't export any useful symbols, so just query the dependencies.
+            oscmd("cd targetroot && %(dpkg_shlibdeps)s -x%(pkg_name)s %(lib_pattern)s %(bin_pattern)s*" % locals())
+            depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip()
+            recommends = ""
+        else:
+            pkg_name = "panda3d" + major_version
+            pkg_dir = "debian/panda3d" + major_version
+
+            # Generate a symbols file so that other packages can know which symbols we export.
+            oscmd("cd targetroot && dpkg-gensymbols -q -ODEBIAN/symbols -v%(pkg_version)s -p%(pkg_name)s -e%(lib_pattern)s" % locals())
+
+            # Library dependencies are required, binary dependencies are recommended.
+            # We explicitly exclude libphysx-extras since we don't want to depend on PhysX.
+            oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_dep --ignore-missing-info -x%(pkg_name)s -xlibphysx-extras %(lib_pattern)s" % locals())
+            oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_rec --ignore-missing-info -x%(pkg_name)s %(bin_pattern)s" % locals())
+
+            # Parse the substvars files generated by dpkg-shlibdeps.
+            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
+                recommends += ", python-wxversion, python-profiler (>= " + PV + "), python-pmw, python-tk (>= " + PV + ")"
+            if PkgSkip("NVIDIACG")==0:
+                depends += ", nvidia-cg-toolkit"
+
+        # Write back the dependencies, and delete the dummy set-up.
+        txt = txt.replace("DEPENDS", depends.strip(', '))
+        txt = txt.replace("RECOMMENDS", recommends.strip(', '))
+        WriteFile("targetroot/DEBIAN/control", txt)
+        oscmd("rm -rf targetroot/debian")
+
+        # Package it all up into a .deb file.
+        oscmd("chmod -R 755 targetroot/DEBIAN")
+        oscmd("chmod 644 targetroot/DEBIAN/control targetroot/DEBIAN/md5sums")
+        if not runtime:
+            oscmd("chmod 644 targetroot/DEBIAN/conffiles targetroot/DEBIAN/symbols")
+        oscmd("fakeroot dpkg-deb -b targetroot %s_%s_%s.deb" % (pkg_name, pkg_version, pkg_arch))
+
+    elif rpmbuild_present:
+        # Invoke installpanda.py to install it into a temporary dir
+        if runtime:
+            InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=outputdir, libdir=GetRPMLibDir())
+        else:
+            InstallPanda(destdir="targetroot", prefix="/usr", outputdir=outputdir, libdir=GetRPMLibDir())
+            oscmd("chmod -R 755 targetroot/usr/share/panda3d")
+
+        oscmd("rpm -E '%_target_cpu' > "+outputdir+"/tmp/architecture.txt")
+        arch = ReadFile(outputdir+"/tmp/architecture.txt").strip()
+        pandasource = os.path.abspath(os.getcwd())
+
+        if runtime:
+            txt = RUNTIME_INSTALLER_SPEC_FILE[1:]
+        else:
+            txt = INSTALLER_SPEC_FILE[1:]
+
+            # Add the MIME associations if we have pview
+            if not PkgSkip("PVIEW"):
+                txt += INSTALLER_SPEC_FILE_PVIEW
+
+            # Add the binaries in /usr/bin explicitly to the spec file
+            for base in os.listdir(outputdir + "/bin"):
+                txt += "/usr/bin/%s\n" % (base)
+
+        # Write out the spec file.
+        txt = txt.replace("VERSION", version)
+        txt = txt.replace("RPMRELEASE", rpmrelease)
+        txt = txt.replace("PANDASOURCE", pandasource)
+        txt = txt.replace("PV", PV)
+        WriteFile("panda3d.spec", txt)
+
+        oscmd("fakeroot rpmbuild --define '_rpmdir "+pandasource+"' --buildroot '"+os.path.abspath("targetroot")+"' -bb panda3d.spec")
+        if runtime:
+            oscmd("mv "+arch+"/panda3d-runtime-"+version+"-"+rpmrelease+"."+arch+".rpm .")
+        else:
+            oscmd("mv "+arch+"/panda3d-"+version+"-"+rpmrelease+"."+arch+".rpm .")
+        oscmd("rm -rf "+arch, True)
+
+    else:
+        exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!")
+
+
+def MakeInstallerOSX(version, runtime=False, **kwargs):
+    outputdir = GetOutputDir()
+
+    if runtime:
+        # Invoke the make_installer script.
+        AddToPathEnv("DYLD_LIBRARY_PATH", outputdir + "/plugins")
+        cmdstr = sys.executable + " "
+        if sys.version_info >= (2, 6):
+            cmdstr += "-B "
+
+        cmdstr += "direct/src/plugin_installer/make_installer.py --version %s" % version
+        oscmd(cmdstr)
+        return
+
+    if "PYTHONVERSION" in SDK:
+        pyver = SDK["PYTHONVERSION"][6:9]
+    else:
+        pyver = "%d.%d" % (sys.version_info[:2])
+
+    dmg_name = "Panda3D-" + version
+    if not pyver.startswith("2."):
+        dmg_name += "-py" + pyver
+    dmg_name += ".dmg"
+
+    import compileall
+    if (os.path.isfile(dmg_name)): oscmd("rm -f %s" % dmg_name)
+    if (os.path.exists("dstroot")): oscmd("rm -rf dstroot")
+    if (os.path.exists("Panda3D-rw.dmg")): oscmd('rm -f Panda3D-rw.dmg')
+
+    oscmd("mkdir -p dstroot/base/Developer/Panda3D/lib")
+    oscmd("mkdir -p dstroot/base/Developer/Panda3D/etc")
+    oscmd("cp %s/etc/Config.prc           dstroot/base/Developer/Panda3D/etc/Config.prc" % outputdir)
+    oscmd("cp %s/etc/Confauto.prc         dstroot/base/Developer/Panda3D/etc/Confauto.prc" % outputdir)
+    oscmd("cp -R %s/models                dstroot/base/Developer/Panda3D/models" % outputdir)
+    oscmd("cp -R doc/LICENSE              dstroot/base/Developer/Panda3D/LICENSE")
+    oscmd("cp -R doc/ReleaseNotes         dstroot/base/Developer/Panda3D/ReleaseNotes")
+    oscmd("cp -R %s/Frameworks            dstroot/base/Developer/Panda3D/Frameworks" % outputdir)
+    if os.path.isdir(outputdir+"/plugins"):
+        oscmd("cp -R %s/plugins           dstroot/base/Developer/Panda3D/plugins" % outputdir)
+
+    # Libraries that shouldn't be in base, but are instead in other modules.
+    no_base_libs = ['libp3ffmpeg', 'libp3fmod_audio', 'libfmodex', 'libfmodexL']
+
+    for base in os.listdir(outputdir+"/lib"):
+        if not base.endswith(".a") and base.split('.')[0] not in no_base_libs:
+            libname = "dstroot/base/Developer/Panda3D/lib/" + base
+            # We really need to specify -R in order not to follow symlinks
+            # On OSX, just specifying -P is not enough to do that.
+            oscmd("cp -R -P " + outputdir + "/lib/" + base + " " + libname)
+
+    oscmd("mkdir -p dstroot/tools/Developer/Panda3D/bin")
+    oscmd("mkdir -p dstroot/tools/Developer/Tools")
+    oscmd("ln -s ../Panda3D/bin dstroot/tools/Developer/Tools/Panda3D")
+    oscmd("mkdir -p dstroot/tools/etc/paths.d")
+    # Trailing newline is important, works around a bug in OSX
+    WriteFile("dstroot/tools/etc/paths.d/Panda3D", "/Developer/Panda3D/bin\n")
+
+    oscmd("mkdir -m 0755 -p dstroot/tools/usr/local/share/man/man1")
+    oscmd("install -m 0644 doc/man/*.1 dstroot/tools/usr/local/share/man/man1/")
+
+    for base in os.listdir(outputdir+"/bin"):
+        binname = "dstroot/tools/Developer/Panda3D/bin/" + base
+        # OSX needs the -R argument to copy symbolic links correctly, it doesn't have -d. How weird.
+        oscmd("cp -R " + outputdir + "/bin/" + base + " " + binname)
+
+    if not PkgSkip("PYTHON"):
+        pyexec = SDK.get("PYTHONEXEC", sys.executable)
+        oscmd("mkdir -p dstroot/pythoncode/usr/local/bin")
+        oscmd("mkdir -p dstroot/pythoncode/Developer/Panda3D/panda3d")
+        oscmd("mkdir -p dstroot/pythoncode/Library/Python/%s/site-packages" % pyver)
+        WriteFile("dstroot/pythoncode/Library/Python/%s/site-packages/Panda3D.pth" % pyver, "/Developer/Panda3D")
+        oscmd("cp -R %s/pandac                dstroot/pythoncode/Developer/Panda3D/pandac" % outputdir)
+        oscmd("cp -R %s/direct                dstroot/pythoncode/Developer/Panda3D/direct" % outputdir)
+        oscmd("ln -s %s                       dstroot/pythoncode/usr/local/bin/ppython" % pyexec)
+        oscmd("cp -R %s/*.so                  dstroot/pythoncode/Developer/Panda3D/" % outputdir, True)
+        oscmd("cp -R %s/*.py                  dstroot/pythoncode/Developer/Panda3D/" % outputdir, True)
+        if os.path.isdir(outputdir+"/Pmw"):
+            oscmd("cp -R %s/Pmw               dstroot/pythoncode/Developer/Panda3D/Pmw" % outputdir)
+            compileall.compile_dir("dstroot/pythoncode/Developer/Panda3D/Pmw")
+        WriteFile("dstroot/pythoncode/Developer/Panda3D/direct/__init__.py", "")
+        for base in os.listdir("dstroot/pythoncode/Developer/Panda3D/direct"):
+            if ((base != "extensions") and (base != "extensions_native")):
+                compileall.compile_dir("dstroot/pythoncode/Developer/Panda3D/direct/"+base)
+
+        suffix = GetExtensionSuffix()
+        for base in os.listdir(outputdir+"/panda3d"):
+            if base.endswith('.py') or (base.endswith(suffix) and '.' not in base[:-len(suffix)]):
+                libname = "dstroot/pythoncode/Developer/Panda3D/panda3d/" + base
+                # We really need to specify -R in order not to follow symlinks
+                # On OSX, just specifying -P is not enough to do that.
+                oscmd("cp -R -P " + outputdir + "/panda3d/" + base + " " + libname)
+
+    if not PkgSkip("FFMPEG"):
+        oscmd("mkdir -p dstroot/ffmpeg/Developer/Panda3D/lib")
+        oscmd("cp -R %s/lib/libp3ffmpeg.* dstroot/ffmpeg/Developer/Panda3D/lib/" % outputdir)
+
+    #if not PkgSkip("OPENAL"):
+    #    oscmd("mkdir -p dstroot/openal/Developer/Panda3D/lib")
+    #    oscmd("cp -R %s/lib/libp3openal_audio.* dstroot/openal/Developer/Panda3D/lib/" % outputdir)
+
+    if not PkgSkip("FMODEX"):
+        oscmd("mkdir -p dstroot/fmodex/Developer/Panda3D/lib")
+        oscmd("cp -R %s/lib/libp3fmod_audio.* dstroot/fmodex/Developer/Panda3D/lib/" % outputdir)
+        oscmd("cp -R %s/lib/libfmodex* dstroot/fmodex/Developer/Panda3D/lib/" % outputdir)
+
+    oscmd("mkdir -p dstroot/headers/Developer/Panda3D/lib")
+    oscmd("cp -R %s/include               dstroot/headers/Developer/Panda3D/include" % outputdir)
+    if os.path.isfile(outputdir + "/lib/libp3pystub.a"):
+        oscmd("cp -R -P %s/lib/libp3pystub.a dstroot/headers/Developer/Panda3D/lib/" % outputdir)
+
+    if os.path.isdir("samples"):
+        oscmd("mkdir -p dstroot/samples/Developer/Examples/Panda3D")
+        oscmd("cp -R samples/* dstroot/samples/Developer/Examples/Panda3D/")
+
+    oscmd("chmod -R 0775 dstroot/*")
+    DeleteVCS("dstroot")
+    DeleteBuildFiles("dstroot")
+    # We need to be root to perform a chown. Bleh.
+    # Fortunately PackageMaker does it for us, on 10.5 and above.
+    #oscmd("chown -R root:admin dstroot/*", True)
+
+    oscmd("mkdir -p dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/")
+    oscmd("mkdir -p dstroot/Panda3D/Panda3D.mpkg/Contents/Resources/en.lproj/")
+
+    pkgs = ["base", "tools", "headers"]
+    if not PkgSkip("PYTHON"):    pkgs.append("pythoncode")
+    if not PkgSkip("FFMPEG"):    pkgs.append("ffmpeg")
+    #if not PkgSkip("OPENAL"):    pkgs.append("openal")
+    if not PkgSkip("FMODEX"):    pkgs.append("fmodex")
+    if os.path.isdir("samples"): pkgs.append("samples")
+    for pkg in pkgs:
+        identifier = "org.panda3d.panda3d.%s.pkg" % pkg
+        plist = open("/tmp/Info_plist", "w")
+        plist.write(Info_plist.format(package_id=identifier, version=version))
+        plist.close()
+        if not os.path.isdir("dstroot/" + pkg):
+            os.makedirs("dstroot/" + pkg)
+
+        if os.path.exists("/usr/bin/pkgbuild"):
+            # This new package builder is used in Lion and above.
+            cmd = '/usr/bin/pkgbuild --identifier ' + identifier + ' --version ' + version + ' --root dstroot/' + pkg + '/ dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg'
+
+        # In older versions, we use PackageMaker.  Apple keeps changing its location.
+        elif os.path.exists("/Developer/usr/bin/packagemaker"):
+            cmd = '/Developer/usr/bin/packagemaker --info /tmp/Info_plist --version ' + version + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
+        elif os.path.exists("/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"):
+            cmd = '/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + version + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
+        elif os.path.exists("/Developer/Tools/PackageMaker.app/Contents/MacOS/PackageMaker"):
+            cmd = '/Developer/Tools/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + version + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
+        elif os.path.exists("/Developer/Tools/packagemaker"):
+            cmd = '/Developer/Tools/packagemaker -build -f dstroot/' + pkg + '/ -p dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg -i /tmp/Info_plist'
+        elif os.path.exists("/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"):
+            cmd = '/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + version + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
+        else:
+            exit("Neither pkgbuild nor PackageMaker could be found!")
+        oscmd(cmd)
+
+    if os.path.isfile("/tmp/Info_plist"):
+        oscmd("rm -f /tmp/Info_plist")
+
+    # Now that we've built all of the individual packages, build the metapackage.
+    dist = open("dstroot/Panda3D/Panda3D.mpkg/Contents/distribution.dist", "w")
+    dist.write('<?xml version="1.0" encoding="utf-8"?>\n')
+    dist.write('<installer-script minSpecVersion="1.000000" authoringTool="com.apple.PackageMaker" authoringToolVersion="3.0.3" authoringToolBuild="174">\n')
+    dist.write('    <title>Panda3D SDK %s</title>\n' % (version))
+    dist.write('    <options customize="always" allow-external-scripts="no" rootVolumeOnly="false"/>\n')
+    dist.write('    <license language="en" mime-type="text/plain">%s</license>\n' % ReadFile("doc/LICENSE"))
+    dist.write('    <choices-outline>\n')
+    for pkg in pkgs:
+        dist.write('        <line choice="%s"/>\n' % (pkg))
+    dist.write('    </choices-outline>\n')
+    dist.write('    <choice id="base" title="Panda3D Base Installation" description="This package contains the Panda3D libraries, configuration files and models/textures that are needed to use Panda3D. Location: /Developer/Panda3D/" start_enabled="false">\n')
+    dist.write('        <pkg-ref id="org.panda3d.panda3d.base.pkg"/>\n')
+    dist.write('    </choice>\n')
+    dist.write('    <choice id="tools" title="Tools" tooltip="Useful tools and model converters to help with Panda3D development" description="This package contains the various utilities that ship with Panda3D, including packaging tools, model converters, and many more. Location: /Developer/Panda3D/bin/">\n')
+    dist.write('        <pkg-ref id="org.panda3d.panda3d.tools.pkg"/>\n')
+    dist.write('    </choice>\n')
+
+    if not PkgSkip("PYTHON"):
+        dist.write('    <choice id="pythoncode" title="Python Support" tooltip="Python bindings for the Panda3D libraries" description="This package contains the \'direct\', \'pandac\' and \'panda3d\' python packages that are needed to do Python development with Panda3D. Location: /Developer/Panda3D/">\n')
+        dist.write('        <pkg-ref id="org.panda3d.panda3d.pythoncode.pkg"/>\n')
+        dist.write('    </choice>\n')
+
+    if not PkgSkip("FFMPEG"):
+        dist.write('    <choice id="ffmpeg" title="FFMpeg Plug-In" tooltip="FFMpeg video and audio decoding plug-in" description="This package contains the FFMpeg plug-in, which is used for decoding video and audio files with OpenAL.')
+        if PkgSkip("VORBIS") and PkgSkip("OPUS"):
+            dist.write('  It is not required for loading .wav files, which Panda3D can read out of the box.">\n')
+        elif PkgSkip("VORBIS"):
+            dist.write('  It is not required for loading .wav or .opus files, which Panda3D can read out of the box.">\n')
+        elif PkgSkip("OPUS"):
+            dist.write('  It is not required for loading .wav or .ogg files, which Panda3D can read out of the box.">\n')
+        else:
+            dist.write('  It is not required for loading .wav, .ogg or .opus files, which Panda3D can read out of the box.">\n')
+        dist.write('        <pkg-ref id="org.panda3d.panda3d.ffmpeg.pkg"/>\n')
+        dist.write('    </choice>\n')
+
+    #if not PkgSkip("OPENAL"):
+    #    dist.write('    <choice id="openal" title="OpenAL Audio Plug-In" tooltip="OpenAL audio output plug-in" description="This package contains the OpenAL audio plug-in, which is an open-source library for playing sounds.">\n')
+    #    dist.write('        <pkg-ref id="org.panda3d.panda3d.openal.pkg"/>\n')
+    #    dist.write('    </choice>\n')
+
+    if not PkgSkip("FMODEX"):
+        dist.write('    <choice id="fmodex" title="FMOD Ex Plug-In" tooltip="FMOD Ex audio output plug-in" description="This package contains the FMOD Ex audio plug-in, which is a commercial library for playing sounds.  It is an optional component as Panda3D can use the open-source alternative OpenAL instead.">\n')
+        dist.write('        <pkg-ref id="org.panda3d.panda3d.fmodex.pkg"/>\n')
+        dist.write('    </choice>\n')
+
+    if os.path.isdir("samples"):
+        dist.write('    <choice id="samples" title="Sample Programs" tooltip="Python sample programs that use Panda3D" description="This package contains the Python sample programs that can help you with learning how to use Panda3D. Location: /Developer/Examples/Panda3D/">\n')
+        dist.write('        <pkg-ref id="org.panda3d.panda3d.samples.pkg"/>\n')
+        dist.write('    </choice>\n')
+
+    dist.write('    <choice id="headers" title="C++ Header Files" tooltip="Header files for C++ development with Panda3D" description="This package contains the C++ header files that are needed in order to do C++ development with Panda3D. You don\'t need this if you want to develop in Python. Location: /Developer/Panda3D/include/" start_selected="false">\n')
+    dist.write('        <pkg-ref id="org.panda3d.panda3d.headers.pkg"/>\n')
+    dist.write('    </choice>\n')
+    for pkg in pkgs:
+        size = GetDirectorySize("dstroot/" + pkg) // 1024
+        dist.write('    <pkg-ref id="org.panda3d.panda3d.%s.pkg" installKBytes="%d" version="1" auth="Root">file:./Contents/Packages/%s.pkg</pkg-ref>\n' % (pkg, size, pkg))
+    dist.write('</installer-script>\n')
+    dist.close()
+
+    oscmd('hdiutil create Panda3D-rw.dmg -volname "Panda3D SDK %s" -srcfolder dstroot/Panda3D' % (version))
+    oscmd('hdiutil convert Panda3D-rw.dmg -format UDBZ -o %s' % (dmg_name))
+    oscmd('rm -f Panda3D-rw.dmg')
+
+
+def MakeInstallerFreeBSD(version, runtime=False, **kwargs):
+    outputdir = GetOutputDir()
+
+    oscmd("rm -rf targetroot +DESC pkg-plist +MANIFEST")
+    oscmd("mkdir targetroot")
+
+    # Invoke installpanda.py to install it into a temporary dir
+    if runtime:
+        InstallRuntime(destdir="targetroot", prefix="/usr/local", outputdir=outputdir)
+    else:
+        InstallPanda(destdir="targetroot", prefix="/usr/local", outputdir=outputdir)
+
+    if not os.path.exists("/usr/sbin/pkg"):
+        exit("Cannot create an installer without pkg")
+
+    plist_txt = ''
+    for root, dirs, files in os.walk("targetroot/usr/local/", True):
+        for f in files:
+            plist_txt += os.path.join(root, f)[21:] + "\n"
+
+    if not runtime:
+        plist_txt += "@postexec /sbin/ldconfig -m /usr/local/lib/panda3d\n"
+        plist_txt += "@postunexec /sbin/ldconfig -R\n"
+
+        for remdir in ("lib/panda3d", "share/panda3d", "include/panda3d"):
+            for root, dirs, files in os.walk("targetroot/usr/local/" + remdir, False):
+                for d in dirs:
+                    plist_txt += "@dir %s\n" % os.path.join(root, d)[21:]
+            plist_txt += "@dir %s\n" % remdir
+
+    oscmd("echo \"`pkg config abi | tr '[:upper:]' '[:lower:]' | cut -d: -f1,2`:*\" > " + outputdir + "/tmp/architecture.txt")
+    pkg_arch = ReadFile(outputdir+"/tmp/architecture.txt").strip()
+
+    dependencies = ''
+    if not PkgSkip("PYTHON"):
+        # If this version of Python was installed from a package or ports, let's mark it as dependency.
+        oscmd("rm -f %s/tmp/python_dep" % outputdir)
+
+        if "PYTHONVERSION" in SDK:
+            pyver_nodot = SDK["PYTHONVERSION"][6:9:2]
+        else:
+            pyver_nodot = "%d%d" % (sys.version_info[:2])
+
+        oscmd("pkg query \"\n\t%%n : {\n\t\torigin : %%o,\n\t\tversion : %%v\n\t},\n\" python%s > %s/tmp/python_dep" % (pyver_nodot, outputdir), True)
+        if os.path.isfile(outputdir + "/tmp/python_dep"):
+            python_pkg = ReadFile(outputdir + "/tmp/python_dep")
+            if python_pkg:
+                dependencies += python_pkg
+
+    manifest_txt = INSTALLER_PKG_MANIFEST_FILE[1:].replace("NAME", 'panda3d' if not runtime else 'panda3d-runtime')
+    manifest_txt = manifest_txt.replace("VERSION", version)
+    manifest_txt = manifest_txt.replace("ARCH", pkg_arch)
+    manifest_txt = manifest_txt.replace("ORIGIN", 'devel/panda3d' if not runtime else 'graphics/panda3d-runtime')
+    manifest_txt = manifest_txt.replace("DEPENDS", dependencies)
+    manifest_txt = manifest_txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024 / 1024))
+
+    WriteFile("pkg-plist", plist_txt)
+    WriteFile("+DESC", INSTALLER_PKG_DESCR_FILE[1:] if not runtime else RUNTIME_INSTALLER_PKG_DESCR_FILE[1:])
+    WriteFile("+MANIFEST", manifest_txt)
+    oscmd("pkg create -p pkg-plist -r %s  -m . -o . %s" % (os.path.abspath("targetroot"), "--verbose" if GetVerbose() else "--quiet"))
+
+
+def MakeInstallerAndroid(version, **kwargs):
+    outputdir = GetOutputDir()
+    oscmd("rm -rf apkroot")
+    oscmd("mkdir apkroot")
+
+    # Also remove the temporary apks.
+    apk_unaligned = os.path.join(outputdir, "tmp", "panda3d-unaligned.apk")
+    apk_unsigned = os.path.join(outputdir, "tmp", "panda3d-unsigned.apk")
+    if os.path.exists(apk_unaligned):
+        os.unlink(apk_unaligned)
+    if os.path.exists(apk_unsigned):
+        os.unlink(apk_unsigned)
+
+    # Compile the Java classes into a Dalvik executable.
+    dx_cmd = "dx --dex --output=apkroot/classes.dex "
+    if GetOptimize() <= 2:
+        dx_cmd += "--debug "
+    if GetVerbose():
+        dx_cmd += "--verbose "
+    if "ANDROID_API" in SDK:
+        dx_cmd += "--min-sdk-version=%d " % (SDK["ANDROID_API"])
+    dx_cmd += os.path.join(outputdir, "classes")
+    oscmd(dx_cmd)
+
+    # Copy the libraries one by one.  In case of library dependencies, strip
+    # off any suffix (eg. libfile.so.1.0), as Android does not support them.
+    source_dir = os.path.join(outputdir, "lib")
+    target_dir = os.path.join("apkroot", "lib", SDK["ANDROID_ABI"])
+    oscmd("mkdir -p %s" % (target_dir))
+
+    # Determine the library directories we should look in.
+    libpath = [source_dir]
+    for dir in os.environ.get("LD_LIBRARY_PATH", "").split(':'):
+        dir = os.path.expandvars(dir)
+        dir = os.path.expanduser(dir)
+        if os.path.isdir(dir):
+            dir = os.path.realpath(dir)
+            if not dir.startswith("/system") and not dir.startswith("/vendor"):
+                libpath.append(dir)
+
+    def copy_library(source, base):
+        # Copy file to destination, stripping version suffix.
+        target = os.path.join(target_dir, base)
+        if not target.endswith('.so'):
+            target = target.rpartition('.so.')[0] + '.so'
+
+        if os.path.isfile(target):
+            # Already processed.
+            return
+
+        oscmd("cp %s %s" % (source, target))
+
+        # Walk through the library dependencies.
+        oscmd("ldd %s | grep .so > %s/tmp/otool-libs.txt" % (target, outputdir), True)
+        for line in open(outputdir + "/tmp/otool-libs.txt", "r"):
+            line = line.strip()
+            if not line:
+                continue
+            if '.so.' in line:
+                dep = line.rpartition('.so.')[0] + '.so'
+                oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True)
+            else:
+                dep = line
+
+            # Find it on the LD_LIBRARY_PATH.
+            for dir in libpath:
+                fulldep = os.path.join(dir, dep)
+                if os.path.isfile(fulldep):
+                    copy_library(os.path.realpath(fulldep), dep)
+                    break
+
+    # Now copy every lib in the lib dir, and its dependencies.
+    for base in os.listdir(source_dir):
+        if not base.startswith('lib'):
+            continue
+        if not base.endswith('.so') and '.so.' not in base:
+            continue
+
+        source = os.path.join(source_dir, base)
+        if os.path.islink(source):
+            continue
+        copy_library(source, base)
+
+    # Same for Python extension modules.  However, Android is strict about
+    # library naming, so we have a special naming scheme for these, in
+    # conjunction with a custom import hook to find these modules.
+    if not PkgSkip("PYTHON"):
+        suffix = GetExtensionSuffix()
+        source_dir = os.path.join(outputdir, "panda3d")
+        for base in os.listdir(source_dir):
+            if not base.endswith(suffix):
+                continue
+            modname = base[:-len(suffix)]
+            if '.' not in modname:
+                source = os.path.join(source_dir, base)
+                copy_library(source, "libpy.panda3d.{}.so".format(modname))
+
+        # Same for standard Python modules.
+        import _ctypes
+        source_dir = os.path.dirname(_ctypes.__file__)
+        for base in os.listdir(source_dir):
+            if not base.endswith('.so'):
+                continue
+            modname = base.partition('.')[0]
+            source = os.path.join(source_dir, base)
+            copy_library(source, "libpy.{}.so".format(modname))
+
+    def copy_python_tree(source_root, target_root):
+        for source_dir, dirs, files in os.walk(source_root):
+            if 'site-packages' in dirs:
+                dirs.remove('site-packages')
+
+            if not any(base.endswith('.py') for base in files):
+                continue
+
+            target_dir = os.path.join(target_root, os.path.relpath(source_dir, source_root))
+            target_dir = os.path.normpath(target_dir)
+            os.makedirs(target_dir, 0o755)
+
+            for base in files:
+                if base.endswith('.py'):
+                    target = os.path.join(target_dir, base)
+                    shutil.copy(os.path.join(source_dir, base), target)
+
+    # Copy the Python standard library to the .apk as well.
+    from distutils.sysconfig import get_python_lib
+    stdlib_source = get_python_lib(False, True)
+    stdlib_target = os.path.join("apkroot", "lib", "python{0}.{1}".format(*sys.version_info))
+    copy_python_tree(stdlib_source, stdlib_target)
+
+    # But also copy over our custom site.py.
+    shutil.copy("panda/src/android/site.py", os.path.join(stdlib_target, "site.py"))
+
+    # And now make a site-packages directory containing our direct/panda3d/pandac modules.
+    for tree in "panda3d", "direct", "pandac":
+        copy_python_tree(os.path.join(outputdir, tree), os.path.join(stdlib_target, "site-packages", tree))
+
+    # Copy the models and config files to the virtual assets filesystem.
+    oscmd("mkdir apkroot/assets")
+    oscmd("cp -R %s apkroot/assets/models" % (os.path.join(outputdir, "models")))
+    oscmd("cp -R %s apkroot/assets/etc" % (os.path.join(outputdir, "etc")))
+
+    # Make an empty res folder.  It's needed for the apk to be installable, apparently.
+    oscmd("mkdir apkroot/res")
+
+    # Now package up the application
+    oscmd("cp panda/src/android/pview_manifest.xml apkroot/AndroidManifest.xml")
+    aapt_cmd = "aapt package"
+    aapt_cmd += " -F %s" % (apk_unaligned)
+    aapt_cmd += " -M apkroot/AndroidManifest.xml"
+    aapt_cmd += " -A apkroot/assets -S apkroot/res"
+    aapt_cmd += " -I $PREFIX/share/aapt/android.jar"
+    oscmd(aapt_cmd)
+
+    # And add all the libraries to it.
+    oscmd("cd apkroot && aapt add ../%s classes.dex" % (apk_unaligned))
+    for path, dirs, files in os.walk('apkroot/lib'):
+        if files:
+            rel = os.path.relpath(path, 'apkroot')
+            oscmd("cd apkroot && aapt add ../%s %s/*" % (apk_unaligned, rel))
+
+    # Now align the .apk, which is necessary for Android to load it.
+    oscmd("zipalign -v -p 4 %s %s" % (apk_unaligned, apk_unsigned))
+
+    # Finally, sign it using a debug key.  This is generated if it doesn't exist.
+    oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned))
+
+    # Clean up.
+    oscmd("rm -rf apkroot")
+    os.unlink(apk_unaligned)
+    os.unlink(apk_unsigned)
+
+
+def MakeInstaller(version, **kwargs):
+    target = GetTarget()
+    if target == 'windows':
+        fn = "Panda3D-"
+        dir = "Panda3D-" + version
+
+        runtime = kwargs.get('runtime', False)
+        if runtime:
+            fn += "Runtime-"
+            title = "Panda3D " + version
+        else:
+            title = "Panda3D SDK " + version
+
+        fn += version
+
+        if "PYTHONVERSION" in SDK:
+            pyver = SDK["PYTHONVERSION"][6:9]
+        else:
+            pyver = "%d.%d" % (sys.version_info[:2])
+
+        if not runtime and pyver != "2.7":
+            fn += '-py' + pyver
+
+        if GetOptimize() <= 2:
+            fn += "-dbg"
+        if GetTargetArch() == 'x64':
+            fn += '-x64'
+            dir += '-x64'
+
+        MakeInstallerNSIS(version, fn + '.exe', title, 'C:\\' + dir, **kwargs)
+        if not runtime:
+            MakeDebugSymbolArchive(fn + '-pdb.zip', dir)
+    elif target == 'linux':
+        MakeInstallerLinux(version, **kwargs)
+    elif target == 'darwin':
+        MakeInstallerOSX(version, **kwargs)
+    elif target == 'freebsd':
+        MakeInstallerFreeBSD(version, **kwargs)
+    elif target == 'android':
+        MakeInstallerAndroid(version, **kwargs)
+    else:
+        exit("Do not know how to make an installer for this platform")
+
+
+if __name__ == "__main__":
+    version = ParsePandaVersion("dtool/PandaVersion.pp")
+
+    parser = OptionParser()
+    parser.add_option('', '--version', dest='version', help='Panda3D version number (default: %s)' % (version), default=version)
+    parser.add_option('', '--debversion', dest='debversion', help='Version number for .deb file', default=None)
+    parser.add_option('', '--rpmrelease', dest='rpmrelease', help='Release number for .rpm file', default='1')
+    parser.add_option('', '--outputdir', dest='outputdir', help='Makepanda\'s output directory (default: built)', default='built')
+    parser.add_option('', '--verbose', dest='verbose', help='Enable verbose output', action='store_true', default=False)
+    parser.add_option('', '--runtime', dest='runtime', help='Runtime instead of SDK', action='store_true', default=False)
+    parser.add_option('', '--lzma', dest='compressor', help='Use LZMA compression', action='store_const', const='lzma', default='zlib')
+    (options, args) = parser.parse_args()
+
+    SetVerbose(options.verbose)
+    SetOutputDir(options.outputdir)
+
+    # Read out the optimize option.
+    opt = ReadFile(os.path.join(options.outputdir, "tmp", "optimize.dat"))
+    SetOptimize(int(opt.strip()))
+
+    # Read out whether we should set PkgSkip("PYTHON") and some others.
+    # Temporary hack; needs better solution.
+    pkg_list = "PYTHON", "NVIDIACG", "FFMPEG", "OPENAL", "FMODEX", "PVIEW", "NVIDIACG", "VORBIS", "OPUS"
+    PkgListSet(pkg_list)
+    for pkg in pkg_list:
+        dat_path = "dtool_have_%s.dat" % (pkg.lower())
+        content = ReadFile(os.path.join(options.outputdir, "tmp", dat_path))
+        if int(content.strip()):
+            PkgEnable(pkg)
+        else:
+            PkgDisable(pkg)
+
+    # Parse the version.
+    match = re.match(r'^\d+\.\d+\.\d+', options.version)
+    if not match:
+        exit("version requires three digits")
+
+    MakeInstaller(version=match.group(),
+                  outputdir=options.outputdir,
+                  optimize=GetOptimize(),
+                  compressor=options.compressor,
+                  debversion=options.debversion,
+                  rpmrelease=options.rpmrelease,
+                  runtime=options.runtime)

+ 34 - 911
makepanda/makepanda.py

@@ -23,7 +23,6 @@ except:
     exit(1)
 
 from makepandacore import *
-from installpanda import *
 from distutils.util import get_platform
 import time
 import os
@@ -93,7 +92,7 @@ PkgListSet(["PYTHON", "DIRECT",                        # Python support
   "ARTOOLKIT", "OPENCV", "DIRECTCAM", "VISION",        # Augmented Reality
   "GTK2",                                              # GTK2 is used for PStats on Unix
   "MFC", "WX", "FLTK",                                 # Used for web plug-in only
-  "ROCKET", "AWESOMIUM",                               # GUI libraries
+  "ROCKET",                                            # GUI libraries
   "CARBON", "COCOA",                                   # Mac OS X toolkits
   "X11",                                               # Unix platform support
   "PANDATOOL", "PVIEW", "DEPLOYTOOLS",                 # Toolchain
@@ -173,14 +172,22 @@ def parseopts(args):
     global COMPRESSOR,THREADCOUNT,OSXTARGET,OSX_ARCHS,HOST_URL
     global DEBVERSION,WHLVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX,RTDIST_VERSION
     global STRDXSDKVERSION, WINDOWS_SDK, MSVC_VERSION, BOOUSEINTELCOMPILER
+
+    # Options for which to display a deprecation warning.
+    removedopts = [
+        "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts",
+        ]
+
+    # All recognized options.
     longopts = [
         "help","distributor=","verbose","runtime","osxtarget=","tests",
         "optimize=","everything","nothing","installer","wheel","rtdist","nocolor",
         "version=","lzma","no-python","threads=","outputdir=","override=",
         "static","host=","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=",
         "directx-sdk=", "windows-sdk=", "msvc-version=", "clean", "use-icl",
-        "universal", "target=", "arch=", "git-commit=", "no-directscripts",
-        "use-touchinput", "no-touchinput"]
+        "universal", "target=", "arch=", "git-commit=",
+        ] + removedopts
+
     anything = 0
     optimize = ""
     target = None
@@ -192,6 +199,7 @@ def parseopts(args):
         longopts.append("no-" + pkg.lower())
         longopts.append(pkg.lower() + "-incdir=")
         longopts.append(pkg.lower() + "-libdir=")
+
     try:
         opts, extras = getopt.getopt(args, "", longopts)
         for option, value in opts:
@@ -232,7 +240,6 @@ def parseopts(args):
             # Backward compatibility, OPENGL was renamed to GL
             elif (option=="--use-opengl"): PkgEnable("GL")
             elif (option=="--no-opengl"): PkgDisable("GL")
-            elif (option=="--no-directscripts"): pass
             elif (option=="--directx-sdk"):
                 STRDXSDKVERSION = value.strip().lower()
                 if STRDXSDKVERSION == '':
@@ -244,6 +251,8 @@ def parseopts(args):
                 MSVC_VERSION = value.strip().lower()
             elif (option=="--use-icl"): BOOUSEINTELCOMPILER = True
             elif (option=="--clean"): clean_build = True
+            elif (option[2:] in removedopts):
+                Warn("Ignoring removed option %s" % (option))
             else:
                 for pkg in PkgListGet():
                     if option == "--use-" + pkg.lower():
@@ -740,7 +749,6 @@ if (COMPILER == "MSVC"):
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cvaux.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/ml.lib")
     if (PkgSkip("OPENCV")==0):   LibName("OPENCV",   GetThirdpartyDir() + "opencv/lib/cxcore.lib")
-    if (PkgSkip("AWESOMIUM")==0):LibName("AWESOMIUM",GetThirdpartyDir() + "awesomium/lib/Awesomium.lib")
     if (PkgSkip("FFMPEG")==0):   LibName("FFMPEG",   GetThirdpartyDir() + "ffmpeg/lib/avcodec.lib")
     if (PkgSkip("FFMPEG")==0):   LibName("FFMPEG",   GetThirdpartyDir() + "ffmpeg/lib/avformat.lib")
     if (PkgSkip("FFMPEG")==0):   LibName("FFMPEG",   GetThirdpartyDir() + "ffmpeg/lib/avutil.lib")
@@ -860,7 +868,6 @@ if (COMPILER == "MSVC"):
         LibName("BULLET", GetThirdpartyDir() + "bullet/lib/BulletSoftBody" + suffix)
 
 if (COMPILER=="GCC"):
-    PkgDisable("AWESOMIUM")
     if GetTarget() != "darwin":
         PkgDisable("CARBON")
         PkgDisable("COCOA")
@@ -2651,6 +2658,11 @@ def WriteConfigSettings():
     # Finally, write a platform.dat with the platform we are compiling for.
     ConditionalWriteFile(GetOutputDir() + '/tmp/platform.dat', PLATFORM)
 
+    # This is useful for tools like makepackage that need to know things about
+    # the build parameters.
+    ConditionalWriteFile(GetOutputDir() + '/tmp/optimize.dat', str(GetOptimize()))
+
+
 WriteConfigSettings()
 
 WarnConflictingFiles()
@@ -2917,8 +2929,6 @@ if not PkgSkip("SKEL"):
     panda_modules.append('skel')
 if not PkgSkip("EGG"):
     panda_modules.append('egg')
-if not PkgSkip("AWESOMIUM"):
-    panda_modules.append('awesomium')
 if not PkgSkip("ODE"):
     panda_modules.append('ode')
 if not PkgSkip("VRPN"):
@@ -3294,7 +3304,6 @@ CopyAllHeaders('panda/src/text')
 CopyAllHeaders('panda/src/grutil')
 if (PkgSkip("VISION")==0):
     CopyAllHeaders('panda/src/vision')
-CopyAllHeaders('panda/src/awesomium')
 if (PkgSkip("FFMPEG")==0):
     CopyAllHeaders('panda/src/ffmpeg')
 CopyAllHeaders('panda/src/tform')
@@ -4469,32 +4478,6 @@ if (PkgSkip("ROCKET") == 0) and (not RUNTIME):
   PyTargetAdd('rocket.pyd', input=COMMON_PANDA_LIBS)
   PyTargetAdd('rocket.pyd', opts=['ROCKET'])
 
-#
-# DIRECTORY: panda/src/p3awesomium
-#
-if PkgSkip("AWESOMIUM") == 0 and not RUNTIME:
-  OPTS=['DIR:panda/src/awesomium', 'BUILDING:PANDAAWESOMIUM',  'AWESOMIUM']
-  TargetAdd('pandaawesomium_composite1.obj', opts=OPTS, input='pandaawesomium_composite1.cxx')
-  TargetAdd('libp3awesomium.dll', input='pandaawesomium_composite1.obj')
-  TargetAdd('libp3awesomium.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libp3awesomium.dll', opts=OPTS)
-
-  OPTS=['DIR:panda/src/awesomium', 'AWESOMIUM']
-  IGATEFILES=GetDirectoryContents('panda/src/awesomium', ["*.h", "*_composite1.cxx"])
-  TargetAdd('libp3awesomium.in', opts=OPTS, input=IGATEFILES)
-  TargetAdd('libp3awesomium.in', opts=['IMOD:panda3d.awesomium', 'ILIB:libp3awesomium', 'SRCDIR:panda/src/awesomium'])
-
-
-  PyTargetAdd('awesomium_module.obj', input='libp3awesomium.in')
-  PyTargetAdd('awesomium_module.obj', opts=OPTS)
-  PyTargetAdd('awesomium_module.obj', opts=['IMOD:panda3d.awesomium', 'ILIB:awesomium', 'IMPORT:panda3d.core'])
-
-  PyTargetAdd('awesomium.pyd', input='awesomium_module.obj')
-  PyTargetAdd('awesomium.pyd', input='libp3awesomium_igate.obj')
-  PyTargetAdd('awesomium.pyd', input='libp3awesomium.dll')
-  PyTargetAdd('awesomium.pyd', input='libp3interrogatedb.dll')
-  PyTargetAdd('awesomium.pyd', input=COMMON_PANDA_LIBS)
-
 #
 # DIRECTORY: panda/src/p3skel
 #
@@ -6863,17 +6846,18 @@ def SequentialMake(tasklist):
             JustBuilt(task[2], task[3])
         i += 1
 
+
 def RunDependencyQueue(tasklist):
     if (THREADCOUNT!=0):
         ParallelMake(tasklist)
     else:
         SequentialMake(tasklist)
 
+
 try:
     RunDependencyQueue(DEPENDENCYQUEUE)
-except:
+finally:
     SaveDependencyCache()
-    raise
 
 # Run the test suite.
 if RUNTESTS:
@@ -6895,879 +6879,18 @@ if RUNTESTS:
 #
 ##########################################################################################
 
-def MakeInstallerNSIS(file, title, installdir):
-    if (os.path.isfile(file)):
-        os.remove(file)
-    elif (os.path.isdir(file)):
-        shutil.rmtree(file)
-
-    pyver = SDK["PYTHONVERSION"][6:9]
-    if GetTargetArch() == 'x64':
-        regview = '64'
-    else:
-        regview = '32'
-        if int(pyver[0]) == 3 and int(pyver[2]) >= 5:
-            pyver += '-32'
-
-    if (RUNTIME):
-        # Invoke the make_installer script.
-        AddToPathEnv("PATH", GetOutputDir() + "\\bin")
-        AddToPathEnv("PATH", GetOutputDir() + "\\plugins")
-
-        cmd = sys.executable + " -B -u " + os.path.join("direct", "src", "plugin_installer", "make_installer.py")
-        cmd += " --version %s --regview %s" % (VERSION, regview)
-
-        if GetTargetArch() == 'x64':
-            cmd += " --install \"$PROGRAMFILES64\\Panda3D\" "
-        else:
-            cmd += " --install \"$PROGRAMFILES32\\Panda3D\" "
-
-        oscmd(cmd)
-        shutil.move(os.path.join("direct", "src", "plugin_installer", "p3d-setup.exe"), file)
-        return
-
-    print("Building "+title+" installer at %s" % (file))
-    if (COMPRESSOR != "lzma"):
-        print("Note: you are using zlib, which is faster, but lzma gives better compression.")
-    if (os.path.exists("nsis-output.exe")):
-        os.remove("nsis-output.exe")
-    WriteFile(GetOutputDir()+"/tmp/__init__.py", "")
-
-    nsis_defs = {
-        'COMPRESSOR'  : COMPRESSOR,
-        'TITLE'       : title,
-        'INSTALLDIR'  : installdir,
-        'OUTFILE'     : '..\\' + file,
-        'BUILT'       : '..\\' + GetOutputDir(),
-        'SOURCE'      : '..',
-        'PYVER'       : pyver,
-        'REGVIEW'     : regview,
-        'EXT_SUFFIX'  : GetExtensionSuffix(),
-    }
-
-    if GetHost() == 'windows':
-        cmd = os.path.join(GetThirdpartyBase(), 'win-nsis', 'makensis') + ' /V2'
-        for item in nsis_defs.items():
-            cmd += ' /D%s="%s"' % item
-    else:
-        cmd = 'makensis -V2'
-        for item in nsis_defs.items():
-            cmd += ' -D%s="%s"' % item
-
-    cmd += ' "makepanda\\installer.nsi"'
-    oscmd(cmd)
-
-def MakeDebugSymbolArchive(zipname, dirname):
-    import zipfile
-    zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
-
-    for fn in glob.glob(os.path.join(GetOutputDir(), 'bin', '*.pdb')):
-        zip.write(fn, dirname + '/bin/' + os.path.basename(fn))
-
-    for fn in glob.glob(os.path.join(GetOutputDir(), 'panda3d', '*.pdb')):
-        zip.write(fn, dirname + '/panda3d/' + os.path.basename(fn))
-
-    for fn in glob.glob(os.path.join(GetOutputDir(), 'plugins', '*.pdb')):
-        zip.write(fn, dirname + '/plugins/' + os.path.basename(fn))
-
-    for fn in glob.glob(os.path.join(GetOutputDir(), 'python', '*.pdb')):
-        zip.write(fn, dirname + '/python/' + os.path.basename(fn))
-
-    for fn in glob.glob(os.path.join(GetOutputDir(), 'python', 'DLLs', '*.pdb')):
-        zip.write(fn, dirname + '/python/DLLs/' + os.path.basename(fn))
-
-    zip.close()
-
-INSTALLER_DEB_FILE="""
-Package: panda3dMAJOR
-Version: VERSION
-Section: libdevel
-Priority: optional
-Architecture: ARCH
-Essential: no
-Depends: DEPENDS
-Recommends: RECOMMENDS
-Provides: panda3d, pythonPV-panda3d
-Conflicts: panda3d, pythonPV-panda3d
-Replaces: panda3d, pythonPV-panda3d
-Maintainer: rdb <[email protected]>
-Installed-Size: INSTSIZE
-Description: Panda3D free 3D engine SDK
- Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
- Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
- .
- This package contains the SDK for development with Panda3D.
-
-"""
-
-RUNTIME_INSTALLER_DEB_FILE="""
-Package: panda3d-runtime
-Version: VERSION
-Section: web
-Priority: optional
-Architecture: ARCH
-Essential: no
-Depends: DEPENDS
-Provides: panda3d-runtime
-Maintainer: rdb <[email protected]>
-Installed-Size: INSTSIZE
-Description: Runtime binary and browser plugin for the Panda3D Game Engine
- This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
-
-"""
-
-
-# We're not putting "python" in the "Requires" field,
-# since the rpm-based distros don't have a common
-# naming for the Python package.
-INSTALLER_SPEC_FILE="""
-Summary: The Panda3D free 3D engine SDK
-Name: panda3d
-Version: VERSION
-Release: RPMRELEASE
-License: BSD License
-Group: Development/Libraries
-BuildRoot: PANDASOURCE/targetroot
-%description
-Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
-Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
-
-This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files.
-%post
-/sbin/ldconfig
-%postun
-/sbin/ldconfig
-%files
-%defattr(-,root,root)
-/etc/Confauto.prc
-/etc/Config.prc
-/usr/share/panda3d
-/etc/ld.so.conf.d/panda3d.conf
-/usr/%_lib/panda3d
-""" + PYTHON_SITEPACKAGES + """
-/usr/include/panda3d
-"""
-if not PkgSkip("PVIEW"):
-    INSTALLER_SPEC_FILE += \
-"""/usr/share/applications/pview.desktop
-/usr/share/mime-info/panda3d.mime
-/usr/share/mime-info/panda3d.keys
-/usr/share/mime/packages/panda3d.xml
-/usr/share/application-registry/panda3d.applications
-"""
-
-RUNTIME_INSTALLER_SPEC_FILE="""
-Summary: Runtime binary and browser plugin for the Panda3D Game Engine
-Name: panda3d-runtime
-Version: VERSION
-Release: RPMRELEASE
-License: BSD License
-Group: Productivity/Graphics/Other
-BuildRoot: PANDASOURCE/targetroot
-%description
-This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
-%files
-%defattr(-,root,root)
-/usr/bin/panda3d
-/usr/%_lib/nppanda3d.so
-/usr/%_lib/mozilla/plugins/nppanda3d.so
-/usr/%_lib/mozilla-firefox/plugins/nppanda3d.so
-/usr/%_lib/xulrunner-addons/plugins/nppanda3d.so
-/usr/share/mime-info/panda3d-runtime.mime
-/usr/share/mime-info/panda3d-runtime.keys
-/usr/share/mime/packages/panda3d-runtime.xml
-/usr/share/application-registry/panda3d-runtime.applications
-/usr/share/applications/*.desktop
-"""
-
-# plist file for Mac OSX
-Info_plist = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-  <key>CFBundleIdentifier</key>
-  <string>%(package_id)s</string>
-  <key>CFBundleShortVersionString</key>
-  <string>%(version)s</string>
-  <key>IFPkgFlagRelocatable</key>
-  <false/>
-  <key>IFPkgFlagAuthorizationAction</key>
-  <string>RootAuthorization</string>
-  <key>IFPkgFlagAllowBackRev</key>
-  <true/>
-</dict>
-</plist>
-"""
-
-# FreeBSD pkg-descr
-INSTALLER_PKG_DESCR_FILE = """
-Panda3D is a game engine which includes graphics, audio, I/O, collision detection, and other abilities relevant to the creation of 3D games. Panda3D is open source and free software under the revised BSD license, and can be used for both free and commercial game development at no financial cost.
-Panda3D's intended game-development language is Python. The engine itself is written in C++, and utilizes an automatic wrapper-generator to expose the complete functionality of the engine in a Python interface.
-
-This package contains the SDK for development with Panda3D, install panda3d-runtime for the runtime files.
-
-WWW: https://www.panda3d.org/
-"""
-
-# FreeBSD pkg-descr
-RUNTIME_INSTALLER_PKG_DESCR_FILE = """
-Runtime binary and browser plugin for the Panda3D Game Engine
-
-This package contains the runtime distribution and browser plugin of the Panda3D engine. It allows you view webpages that contain Panda3D content and to run games created with Panda3D that are packaged as .p3d file.
-
-WWW: https://www.panda3d.org/
-"""
-
-# FreeBSD PKG Manifest template file
-INSTALLER_PKG_MANIFEST_FILE = """
-name: NAME
-version: VERSION
-arch: ARCH
-origin: ORIGIN
-comment: "Panda3D free 3D engine SDK"
-www: https://www.panda3d.org
-maintainer: rdb <[email protected]>
-prefix: /usr/local
-flatsize: INSTSIZEMB
-deps: {DEPENDS}
-"""
-
-def MakeInstallerLinux():
-    if not RUNTIME and not PkgSkip("PYTHON"):
-        PYTHONV = SDK["PYTHONVERSION"].rstrip('dmu')
-    else:
-        PYTHONV = "python"
-    PV = PYTHONV.replace("python", "")
-
-    # Clean and set up a directory to install Panda3D into
-    oscmd("rm -rf targetroot data.tar.gz control.tar.gz panda3d.spec")
-    oscmd("mkdir --mode=0755 targetroot")
-
-    dpkg_present = False
-    if os.path.exists("/usr/bin/dpkg-architecture") and os.path.exists("/usr/bin/dpkg-deb"):
-        dpkg_present = True
-    rpmbuild_present = False
-    if os.path.exists("/usr/bin/rpmbuild"):
-        rpmbuild_present = True
-
-    if dpkg_present and rpmbuild_present:
-        Warn("both dpkg and rpmbuild present.")
-
-    if dpkg_present:
-        # Invoke installpanda.py to install it into a temporary dir
-        lib_dir = GetDebLibDir()
-        if RUNTIME:
-            InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=lib_dir)
-        else:
-            InstallPanda(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=lib_dir)
-            oscmd("chmod -R 755 targetroot/usr/share/panda3d")
-            oscmd("mkdir -m 0755 -p targetroot/usr/share/man/man1")
-            oscmd("install -m 0644 doc/man/*.1 targetroot/usr/share/man/man1/")
-
-        oscmd("dpkg --print-architecture > "+GetOutputDir()+"/tmp/architecture.txt")
-        pkg_arch = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip()
-        if (RUNTIME):
-            txt = RUNTIME_INSTALLER_DEB_FILE[1:]
-        else:
-            txt = INSTALLER_DEB_FILE[1:]
-        txt = txt.replace("VERSION", DEBVERSION).replace("ARCH", pkg_arch).replace("PV", PV).replace("MAJOR", MAJOR_VERSION)
-        txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024))
-        oscmd("mkdir --mode=0755 -p targetroot/DEBIAN")
-        oscmd("cd targetroot && (find usr -type f -exec md5sum {} ;) > DEBIAN/md5sums")
-        if (not RUNTIME):
-          oscmd("cd targetroot && (find etc -type f -exec md5sum {} ;) >> DEBIAN/md5sums")
-          WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n")
-        WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n")
-        oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm")
-
-        # Determine the package name and the locations that
-        # dpkg-shlibdeps should look in for executables.
-        pkg_version = DEBVERSION
-        if RUNTIME:
-            pkg_name = "panda3d-runtime"
-            lib_pattern = "debian/%s/usr/%s/*.so" % (pkg_name, lib_dir)
-        else:
-            pkg_name = "panda3d" + MAJOR_VERSION
-            lib_pattern = "debian/%s/usr/%s/panda3d/*.so*" % (pkg_name, lib_dir)
-        bin_pattern = "debian/%s/usr/bin/*" % (pkg_name)
-
-        # dpkg-shlibdeps looks in the debian/{pkg_name}/DEBIAN/shlibs directory
-        # and also expects a debian/control file, so we create this dummy set-up.
-        oscmd("mkdir targetroot/debian")
-        oscmd("ln -s .. targetroot/debian/" + pkg_name)
-        WriteFile("targetroot/debian/control", "")
-
-        dpkg_shlibdeps = "dpkg-shlibdeps"
-        if GetVerbose():
-            dpkg_shlibdeps += " -v"
-
-        if RUNTIME:
-            # The runtime doesn't export any useful symbols, so just query the dependencies.
-            oscmd("cd targetroot && %(dpkg_shlibdeps)s -x%(pkg_name)s %(lib_pattern)s %(bin_pattern)s*" % locals())
-            depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip()
-            recommends = ""
-        else:
-            pkg_name = "panda3d" + MAJOR_VERSION
-            pkg_dir = "debian/panda3d" + MAJOR_VERSION
-
-            # Generate a symbols file so that other packages can know which symbols we export.
-            oscmd("cd targetroot && dpkg-gensymbols -q -ODEBIAN/symbols -v%(pkg_version)s -p%(pkg_name)s -e%(lib_pattern)s" % locals())
-
-            # Library dependencies are required, binary dependencies are recommended.
-            # We explicitly exclude libphysx-extras since we don't want to depend on PhysX.
-            oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_dep --ignore-missing-info -x%(pkg_name)s -xlibphysx-extras %(lib_pattern)s" % locals())
-            oscmd("cd targetroot && LD_LIBRARY_PATH=usr/%(lib_dir)s/panda3d %(dpkg_shlibdeps)s -Tdebian/substvars_rec --ignore-missing-info -x%(pkg_name)s %(bin_pattern)s" % locals())
-
-            # Parse the substvars files generated by dpkg-shlibdeps.
-            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
-                recommends += ", python-wxversion, python-profiler (>= " + PV + "), python-pmw, python-tk (>= " + PV + ")"
-            if PkgSkip("NVIDIACG")==0:
-                depends += ", nvidia-cg-toolkit"
-
-        # Write back the dependencies, and delete the dummy set-up.
-        txt = txt.replace("DEPENDS", depends.strip(', '))
-        txt = txt.replace("RECOMMENDS", recommends.strip(', '))
-        WriteFile("targetroot/DEBIAN/control", txt)
-        oscmd("rm -rf targetroot/debian")
-
-        # Package it all up into a .deb file.
-        oscmd("chmod -R 755 targetroot/DEBIAN")
-        oscmd("chmod 644 targetroot/DEBIAN/control targetroot/DEBIAN/md5sums")
-        if not RUNTIME:
-            oscmd("chmod 644 targetroot/DEBIAN/conffiles targetroot/DEBIAN/symbols")
-        oscmd("fakeroot dpkg-deb -b targetroot %s_%s_%s.deb" % (pkg_name, pkg_version, pkg_arch))
-
-    elif rpmbuild_present:
-        # Invoke installpanda.py to install it into a temporary dir
-        if RUNTIME:
-            InstallRuntime(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetRPMLibDir())
-        else:
-            InstallPanda(destdir="targetroot", prefix="/usr", outputdir=GetOutputDir(), libdir=GetRPMLibDir())
-            oscmd("chmod -R 755 targetroot/usr/share/panda3d")
-
-        oscmd("rpm -E '%_target_cpu' > "+GetOutputDir()+"/tmp/architecture.txt")
-        ARCH = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip()
-        pandasource = os.path.abspath(os.getcwd())
-
-        if RUNTIME:
-            txt = RUNTIME_INSTALLER_SPEC_FILE[1:]
-        else:
-            txt = INSTALLER_SPEC_FILE[1:]
-            # Add the binaries in /usr/bin explicitly to the spec file
-            for base in os.listdir(GetOutputDir() + "/bin"):
-                txt += "/usr/bin/%s\n" % (base)
-
-        # Write out the spec file.
-        txt = txt.replace("VERSION", VERSION)
-        txt = txt.replace("RPMRELEASE", RPMRELEASE)
-        txt = txt.replace("PANDASOURCE", pandasource)
-        txt = txt.replace("PV", PV)
-        WriteFile("panda3d.spec", txt)
-
-        oscmd("fakeroot rpmbuild --define '_rpmdir "+pandasource+"' --buildroot '"+os.path.abspath("targetroot")+"' -bb panda3d.spec")
-        if (RUNTIME):
-            oscmd("mv "+ARCH+"/panda3d-runtime-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .")
-        else:
-            oscmd("mv "+ARCH+"/panda3d-"+VERSION+"-"+RPMRELEASE+"."+ARCH+".rpm .")
-        oscmd("rm -rf "+ARCH, True)
-
-    else:
-        exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!")
-
-def MakeInstallerOSX():
-    if (RUNTIME):
-        # Invoke the make_installer script.
-        AddToPathEnv("DYLD_LIBRARY_PATH", GetOutputDir() + "/plugins")
-        cmdstr = sys.executable + " "
-        if sys.version_info >= (2, 6):
-            cmdstr += "-B "
-
-        cmdstr += "direct/src/plugin_installer/make_installer.py --version %s" % VERSION
-        oscmd(cmdstr)
-        return
-
-    dmg_name = "Panda3D-" + VERSION
-    if not SDK["PYTHONVERSION"].startswith("python2."):
-        dmg_name += '-py' + SDK["PYTHONVERSION"][6:9]
-    dmg_name += ".dmg"
-
-    import compileall
-    if (os.path.isfile(dmg_name)): oscmd("rm -f %s" % dmg_name)
-    if (os.path.exists("dstroot")): oscmd("rm -rf dstroot")
-    if (os.path.exists("Panda3D-rw.dmg")): oscmd('rm -f Panda3D-rw.dmg')
-
-    oscmd("mkdir -p dstroot/base/Developer/Panda3D/lib")
-    oscmd("mkdir -p dstroot/base/Developer/Panda3D/etc")
-    oscmd("cp %s/etc/Config.prc           dstroot/base/Developer/Panda3D/etc/Config.prc" % GetOutputDir())
-    oscmd("cp %s/etc/Confauto.prc         dstroot/base/Developer/Panda3D/etc/Confauto.prc" % GetOutputDir())
-    oscmd("cp -R %s/models                dstroot/base/Developer/Panda3D/models" % GetOutputDir())
-    oscmd("cp -R doc/LICENSE              dstroot/base/Developer/Panda3D/LICENSE")
-    oscmd("cp -R doc/ReleaseNotes         dstroot/base/Developer/Panda3D/ReleaseNotes")
-    oscmd("cp -R %s/Frameworks            dstroot/base/Developer/Panda3D/Frameworks" % GetOutputDir())
-    if os.path.isdir(GetOutputDir()+"/plugins"):
-        oscmd("cp -R %s/plugins           dstroot/base/Developer/Panda3D/plugins" % GetOutputDir())
-
-    # Libraries that shouldn't be in base, but are instead in other modules.
-    no_base_libs = ['libp3ffmpeg', 'libp3fmod_audio', 'libfmodex', 'libfmodexL']
-
-    for base in os.listdir(GetOutputDir()+"/lib"):
-        if not base.endswith(".a") and base.split('.')[0] not in no_base_libs:
-            libname = "dstroot/base/Developer/Panda3D/lib/" + base
-            # We really need to specify -R in order not to follow symlinks
-            # On OSX, just specifying -P is not enough to do that.
-            oscmd("cp -R -P " + GetOutputDir() + "/lib/" + base + " " + libname)
-
-    oscmd("mkdir -p dstroot/tools/Developer/Panda3D/bin")
-    oscmd("mkdir -p dstroot/tools/Developer/Tools")
-    oscmd("ln -s ../Panda3D/bin dstroot/tools/Developer/Tools/Panda3D")
-    oscmd("mkdir -p dstroot/tools/etc/paths.d")
-    # Trailing newline is important, works around a bug in OSX
-    WriteFile("dstroot/tools/etc/paths.d/Panda3D", "/Developer/Panda3D/bin\n")
-
-    oscmd("mkdir -m 0755 -p dstroot/tools/usr/local/share/man/man1")
-    oscmd("install -m 0644 doc/man/*.1 dstroot/tools/usr/local/share/man/man1/")
-
-    for base in os.listdir(GetOutputDir()+"/bin"):
-        binname = "dstroot/tools/Developer/Panda3D/bin/" + base
-        # OSX needs the -R argument to copy symbolic links correctly, it doesn't have -d. How weird.
-        oscmd("cp -R " + GetOutputDir() + "/bin/" + base + " " + binname)
-
-    if PkgSkip("PYTHON")==0:
-        PV = SDK["PYTHONVERSION"][6:9]
-        oscmd("mkdir -p dstroot/pythoncode/usr/local/bin")
-        oscmd("mkdir -p dstroot/pythoncode/Developer/Panda3D/panda3d")
-        oscmd("mkdir -p dstroot/pythoncode/Library/Python/%s/site-packages" % PV)
-        WriteFile("dstroot/pythoncode/Library/Python/%s/site-packages/Panda3D.pth" % PV, "/Developer/Panda3D")
-        oscmd("cp -R %s/pandac                dstroot/pythoncode/Developer/Panda3D/pandac" % GetOutputDir())
-        oscmd("cp -R %s/direct                dstroot/pythoncode/Developer/Panda3D/direct" % GetOutputDir())
-        oscmd("ln -s %s                       dstroot/pythoncode/usr/local/bin/ppython" % SDK["PYTHONEXEC"])
-        oscmd("cp -R %s/*.so                  dstroot/pythoncode/Developer/Panda3D/" % GetOutputDir(), True)
-        oscmd("cp -R %s/*.py                  dstroot/pythoncode/Developer/Panda3D/" % GetOutputDir(), True)
-        if os.path.isdir(GetOutputDir()+"/Pmw"):
-            oscmd("cp -R %s/Pmw               dstroot/pythoncode/Developer/Panda3D/Pmw" % GetOutputDir())
-            compileall.compile_dir("dstroot/pythoncode/Developer/Panda3D/Pmw")
-        WriteFile("dstroot/pythoncode/Developer/Panda3D/direct/__init__.py", "")
-        for base in os.listdir("dstroot/pythoncode/Developer/Panda3D/direct"):
-            if ((base != "extensions") and (base != "extensions_native")):
-                compileall.compile_dir("dstroot/pythoncode/Developer/Panda3D/direct/"+base)
-
-        suffix = GetExtensionSuffix()
-        for base in os.listdir(GetOutputDir()+"/panda3d"):
-            if base.endswith('.py') or (base.endswith(suffix) and '.' not in base[:-len(suffix)]):
-                libname = "dstroot/pythoncode/Developer/Panda3D/panda3d/" + base
-                # We really need to specify -R in order not to follow symlinks
-                # On OSX, just specifying -P is not enough to do that.
-                oscmd("cp -R -P " + GetOutputDir() + "/panda3d/" + base + " " + libname)
-
-    if not PkgSkip("FFMPEG"):
-        oscmd("mkdir -p dstroot/ffmpeg/Developer/Panda3D/lib")
-        oscmd("cp -R %s/lib/libp3ffmpeg.* dstroot/ffmpeg/Developer/Panda3D/lib/" % GetOutputDir())
-
-    #if not PkgSkip("OPENAL"):
-    #    oscmd("mkdir -p dstroot/openal/Developer/Panda3D/lib")
-    #    oscmd("cp -R %s/lib/libp3openal_audio.* dstroot/openal/Developer/Panda3D/lib/" % GetOutputDir())
-
-    if not PkgSkip("FMODEX"):
-        oscmd("mkdir -p dstroot/fmodex/Developer/Panda3D/lib")
-        oscmd("cp -R %s/lib/libp3fmod_audio.* dstroot/fmodex/Developer/Panda3D/lib/" % GetOutputDir())
-        oscmd("cp -R %s/lib/libfmodex* dstroot/fmodex/Developer/Panda3D/lib/" % GetOutputDir())
-
-    oscmd("mkdir -p dstroot/headers/Developer/Panda3D/lib")
-    oscmd("cp -R %s/include               dstroot/headers/Developer/Panda3D/include" % GetOutputDir())
-    if os.path.isfile(GetOutputDir() + "/lib/libp3pystub.a"):
-        oscmd("cp -R -P %s/lib/libp3pystub.a dstroot/headers/Developer/Panda3D/lib/" % GetOutputDir())
-
-    if os.path.isdir("samples"):
-        oscmd("mkdir -p dstroot/samples/Developer/Examples/Panda3D")
-        oscmd("cp -R samples/* dstroot/samples/Developer/Examples/Panda3D/")
-
-    oscmd("chmod -R 0775 dstroot/*")
-    DeleteVCS("dstroot")
-    DeleteBuildFiles("dstroot")
-    # We need to be root to perform a chown. Bleh.
-    # Fortunately PackageMaker does it for us, on 10.5 and above.
-    #oscmd("chown -R root:admin dstroot/*", True)
-
-    oscmd("mkdir -p dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/")
-    oscmd("mkdir -p dstroot/Panda3D/Panda3D.mpkg/Contents/Resources/en.lproj/")
-
-    pkgs = ["base", "tools", "headers"]
-    if not PkgSkip("PYTHON"):    pkgs.append("pythoncode")
-    if not PkgSkip("FFMPEG"):    pkgs.append("ffmpeg")
-    #if not PkgSkip("OPENAL"):    pkgs.append("openal")
-    if not PkgSkip("FMODEX"):    pkgs.append("fmodex")
-    if os.path.isdir("samples"): pkgs.append("samples")
-    for pkg in pkgs:
-        identifier = "org.panda3d.panda3d.%s.pkg" % pkg
-        plist = open("/tmp/Info_plist", "w")
-        plist.write(Info_plist % { "package_id" : identifier, "version" : VERSION })
-        plist.close()
-        if not os.path.isdir("dstroot/" + pkg):
-            os.makedirs("dstroot/" + pkg)
-
-        if OSXTARGET and OSXTARGET <= (10, 5):
-            target = '--target %d.%d' % (OSXTARGET)
-        else:
-            target = ''
-
-        if os.path.exists("/usr/bin/pkgbuild"):
-            # This new package builder is used in Lion and above.
-            cmd = '/usr/bin/pkgbuild --identifier ' + identifier + ' --version ' + VERSION + ' --root dstroot/' + pkg + '/ dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg'
-
-        # In older versions, we use PackageMaker.  Apple keeps changing its location.
-        elif os.path.exists("/Developer/usr/bin/packagemaker"):
-            cmd = '/Developer/usr/bin/packagemaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
-        elif os.path.exists("/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"):
-            cmd = '/Applications/Xcode.app/Contents/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
-        elif os.path.exists("/Developer/Tools/PackageMaker.app/Contents/MacOS/PackageMaker"):
-            cmd = '/Developer/Tools/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
-        elif os.path.exists("/Developer/Tools/packagemaker"):
-            cmd = '/Developer/Tools/packagemaker -build -f dstroot/' + pkg + '/ -p dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg -i /tmp/Info_plist'
-        elif os.path.exists("/Applications/PackageMaker.app/Contents/MacOS/PackageMaker"):
-            cmd = '/Applications/PackageMaker.app/Contents/MacOS/PackageMaker --info /tmp/Info_plist --version ' + VERSION + ' --out dstroot/Panda3D/Panda3D.mpkg/Contents/Packages/' + pkg + '.pkg ' + target + ' --domain system --root dstroot/' + pkg + '/ --no-relocate'
-        else:
-            exit("Neither pkgbuild nor PackageMaker could be found!")
-        oscmd(cmd)
-
-    if os.path.isfile("/tmp/Info_plist"):
-        oscmd("rm -f /tmp/Info_plist")
-
-    # Now that we've built all of the individual packages, build the metapackage.
-    dist = open("dstroot/Panda3D/Panda3D.mpkg/Contents/distribution.dist", "w")
-    dist.write('<?xml version="1.0" encoding="utf-8"?>\n')
-    dist.write('<installer-script minSpecVersion="1.000000" authoringTool="com.apple.PackageMaker" authoringToolVersion="3.0.3" authoringToolBuild="174">\n')
-    dist.write('    <title>Panda3D SDK %s</title>\n' % (VERSION))
-    dist.write('    <options customize="always" allow-external-scripts="no" rootVolumeOnly="false"/>\n')
-    dist.write('    <license language="en" mime-type="text/plain">%s</license>\n' % ReadFile("doc/LICENSE"))
-    dist.write('    <choices-outline>\n')
-    for pkg in pkgs:
-        dist.write('        <line choice="%s"/>\n' % (pkg))
-    dist.write('    </choices-outline>\n')
-    dist.write('    <choice id="base" title="Panda3D Base Installation" description="This package contains the Panda3D libraries, configuration files and models/textures that are needed to use Panda3D. Location: /Developer/Panda3D/" start_enabled="false">\n')
-    dist.write('        <pkg-ref id="org.panda3d.panda3d.base.pkg"/>\n')
-    dist.write('    </choice>\n')
-    dist.write('    <choice id="tools" title="Tools" tooltip="Useful tools and model converters to help with Panda3D development" description="This package contains the various utilities that ship with Panda3D, including packaging tools, model converters, and many more. Location: /Developer/Panda3D/bin/">\n')
-    dist.write('        <pkg-ref id="org.panda3d.panda3d.tools.pkg"/>\n')
-    dist.write('    </choice>\n')
-
-    if not PkgSkip("PYTHON"):
-        dist.write('    <choice id="pythoncode" title="Python Support" tooltip="Python bindings for the Panda3D libraries" description="This package contains the \'direct\', \'pandac\' and \'panda3d\' python packages that are needed to do Python development with Panda3D. Location: /Developer/Panda3D/">\n')
-        dist.write('        <pkg-ref id="org.panda3d.panda3d.pythoncode.pkg"/>\n')
-        dist.write('    </choice>\n')
-
-    if not PkgSkip("FFMPEG"):
-        dist.write('    <choice id="ffmpeg" title="FFMpeg Plug-In" tooltip="FFMpeg video and audio decoding plug-in" description="This package contains the FFMpeg plug-in, which is used for decoding video and audio files with OpenAL.')
-        if PkgSkip("VORBIS") and PkgSkip("OPUS"):
-            dist.write('  It is not required for loading .wav files, which Panda3D can read out of the box.">\n')
-        elif PkgSkip("VORBIS"):
-            dist.write('  It is not required for loading .wav or .opus files, which Panda3D can read out of the box.">\n')
-        elif PkgSkip("OPUS"):
-            dist.write('  It is not required for loading .wav or .ogg files, which Panda3D can read out of the box.">\n')
-        else:
-            dist.write('  It is not required for loading .wav, .ogg or .opus files, which Panda3D can read out of the box.">\n')
-        dist.write('        <pkg-ref id="org.panda3d.panda3d.ffmpeg.pkg"/>\n')
-        dist.write('    </choice>\n')
-
-    #if not PkgSkip("OPENAL"):
-    #    dist.write('    <choice id="openal" title="OpenAL Audio Plug-In" tooltip="OpenAL audio output plug-in" description="This package contains the OpenAL audio plug-in, which is an open-source library for playing sounds.">\n')
-    #    dist.write('        <pkg-ref id="org.panda3d.panda3d.openal.pkg"/>\n')
-    #    dist.write('    </choice>\n')
-
-    if not PkgSkip("FMODEX"):
-        dist.write('    <choice id="fmodex" title="FMOD Ex Plug-In" tooltip="FMOD Ex audio output plug-in" description="This package contains the FMOD Ex audio plug-in, which is a commercial library for playing sounds.  It is an optional component as Panda3D can use the open-source alternative OpenAL instead.">\n')
-        dist.write('        <pkg-ref id="org.panda3d.panda3d.fmodex.pkg"/>\n')
-        dist.write('    </choice>\n')
-
-    if os.path.isdir("samples"):
-        dist.write('    <choice id="samples" title="Sample Programs" tooltip="Python sample programs that use Panda3D" description="This package contains the Python sample programs that can help you with learning how to use Panda3D. Location: /Developer/Examples/Panda3D/">\n')
-        dist.write('        <pkg-ref id="org.panda3d.panda3d.samples.pkg"/>\n')
-        dist.write('    </choice>\n')
-
-    dist.write('    <choice id="headers" title="C++ Header Files" tooltip="Header files for C++ development with Panda3D" description="This package contains the C++ header files that are needed in order to do C++ development with Panda3D. You don\'t need this if you want to develop in Python. Location: /Developer/Panda3D/include/" start_selected="false">\n')
-    dist.write('        <pkg-ref id="org.panda3d.panda3d.headers.pkg"/>\n')
-    dist.write('    </choice>\n')
-    for pkg in pkgs:
-        size = GetDirectorySize("dstroot/" + pkg) // 1024
-        dist.write('    <pkg-ref id="org.panda3d.panda3d.%s.pkg" installKBytes="%d" version="1" auth="Root">file:./Contents/Packages/%s.pkg</pkg-ref>\n' % (pkg, size, pkg))
-    dist.write('</installer-script>\n')
-    dist.close()
-
-    oscmd('hdiutil create Panda3D-rw.dmg -volname "Panda3D SDK %s" -srcfolder dstroot/Panda3D' % (VERSION))
-    oscmd('hdiutil convert Panda3D-rw.dmg -format UDBZ -o %s' % (dmg_name))
-    oscmd('rm -f Panda3D-rw.dmg')
-
-def MakeInstallerFreeBSD():
-    oscmd("rm -rf targetroot +DESC pkg-plist +MANIFEST")
-    oscmd("mkdir targetroot")
-
-    # Invoke installpanda.py to install it into a temporary dir
-    if RUNTIME:
-        InstallRuntime(destdir = "targetroot", prefix = "/usr/local", outputdir = GetOutputDir())
-    else:
-        InstallPanda(destdir = "targetroot", prefix = "/usr/local", outputdir = GetOutputDir())
-
-    if not os.path.exists("/usr/sbin/pkg"):
-        exit("Cannot create an installer without pkg")
-
-    plist_txt = ''
-    for root, dirs, files in os.walk("targetroot/usr/local/", True):
-        for f in files:
-            plist_txt += os.path.join(root, f)[21:] + "\n"
-
-    if not RUNTIME:
-        plist_txt += "@postexec /sbin/ldconfig -m /usr/local/lib/panda3d\n"
-        plist_txt += "@postunexec /sbin/ldconfig -R\n"
-
-        for remdir in ("lib/panda3d", "share/panda3d", "include/panda3d"):
-            for root, dirs, files in os.walk("targetroot/usr/local/" + remdir, False):
-                for d in dirs:
-                    plist_txt += "@dir %s\n" % os.path.join(root, d)[21:]
-            plist_txt += "@dir %s\n" % remdir
-
-    oscmd("echo \"`pkg config abi | tr '[:upper:]' '[:lower:]' | cut -d: -f1,2`:*\" > " + GetOutputDir() + "/tmp/architecture.txt")
-    pkg_arch = ReadFile(GetOutputDir()+"/tmp/architecture.txt").strip()
-
-    dependencies = ''
-    if PkgSkip("PYTHON") == 0:
-        # If this version of Python was installed from a package or ports, let's mark it as dependency.
-        oscmd("rm -f %s/tmp/python_dep" % GetOutputDir())
-        oscmd("pkg query \"\n\t%%n : {\n\t\torigin : %%o,\n\t\tversion : %%v\n\t},\n\" python%s > %s/tmp/python_dep" % (SDK["PYTHONVERSION"][6:9:2], GetOutputDir()), True)
-        if os.path.isfile(GetOutputDir() + "/tmp/python_dep"):
-            python_pkg = ReadFile(GetOutputDir() + "/tmp/python_dep")
-            if python_pkg:
-                dependencies += python_pkg
-
-    manifest_txt = INSTALLER_PKG_MANIFEST_FILE[1:].replace("NAME", 'panda3d' if not RUNTIME else 'panda3d-runtime')
-    manifest_txt = manifest_txt.replace("VERSION", VERSION)
-    manifest_txt = manifest_txt.replace("ARCH", pkg_arch)
-    manifest_txt = manifest_txt.replace("ORIGIN", 'devel/panda3d' if not RUNTIME else 'graphics/panda3d-runtime')
-    manifest_txt = manifest_txt.replace("DEPENDS", dependencies)
-    manifest_txt = manifest_txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024 / 1024))
-
-    WriteFile("pkg-plist", plist_txt)
-    WriteFile("+DESC", INSTALLER_PKG_DESCR_FILE[1:] if not RUNTIME else RUNTIME_INSTALLER_PKG_DESCR_FILE[1:])
-    WriteFile("+MANIFEST", manifest_txt)
-    oscmd("pkg create -p pkg-plist -r %s  -m . -o . %s" % (os.path.abspath("targetroot"), "--verbose" if GetVerbose() else "--quiet"))
-
-def MakeInstallerAndroid():
-    oscmd("rm -rf apkroot")
-    oscmd("mkdir apkroot")
-
-    # Also remove the temporary apks.
-    apk_unaligned = os.path.join(GetOutputDir(), "tmp", "panda3d-unaligned.apk")
-    apk_unsigned = os.path.join(GetOutputDir(), "tmp", "panda3d-unsigned.apk")
-    if os.path.exists(apk_unaligned):
-        os.unlink(apk_unaligned)
-    if os.path.exists(apk_unsigned):
-        os.unlink(apk_unsigned)
-
-    # Compile the Java classes into a Dalvik executable.
-    dx_cmd = "dx --dex --output=apkroot/classes.dex "
-    if GetOptimize() <= 2:
-        dx_cmd += "--debug "
-    if GetVerbose():
-        dx_cmd += "--verbose "
-    if "ANDROID_API" in SDK:
-        dx_cmd += "--min-sdk-version=%d " % (SDK["ANDROID_API"])
-    dx_cmd += os.path.join(GetOutputDir(), "classes")
-    oscmd(dx_cmd)
-
-    # Copy the libraries one by one.  In case of library dependencies, strip
-    # off any suffix (eg. libfile.so.1.0), as Android does not support them.
-    source_dir = os.path.join(GetOutputDir(), "lib")
-    target_dir = os.path.join("apkroot", "lib", SDK["ANDROID_ABI"])
-    oscmd("mkdir -p %s" % (target_dir))
-
-    # Determine the library directories we should look in.
-    libpath = [source_dir]
-    for dir in os.environ.get("LD_LIBRARY_PATH", "").split(':'):
-        dir = os.path.expandvars(dir)
-        dir = os.path.expanduser(dir)
-        if os.path.isdir(dir):
-            dir = os.path.realpath(dir)
-            if not dir.startswith("/system") and not dir.startswith("/vendor"):
-                libpath.append(dir)
-
-    def copy_library(source, base):
-        # Copy file to destination, stripping version suffix.
-        target = os.path.join(target_dir, base)
-        if not target.endswith('.so'):
-            target = target.rpartition('.so.')[0] + '.so'
-
-        if os.path.isfile(target):
-            # Already processed.
-            return
-
-        oscmd("cp %s %s" % (source, target))
-
-        # Walk through the library dependencies.
-        oscmd("ldd %s | grep .so > %s/tmp/otool-libs.txt" % (target, GetOutputDir()), True)
-        for line in open(GetOutputDir() + "/tmp/otool-libs.txt", "r"):
-            line = line.strip()
-            if not line:
-                continue
-            if '.so.' in line:
-                dep = line.rpartition('.so.')[0] + '.so'
-                oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True)
-            else:
-                dep = line
-
-            # Find it on the LD_LIBRARY_PATH.
-            for dir in libpath:
-                fulldep = os.path.join(dir, dep)
-                if os.path.isfile(fulldep):
-                    copy_library(os.path.realpath(fulldep), dep)
-                    break
-
-    # Now copy every lib in the lib dir, and its dependencies.
-    for base in os.listdir(source_dir):
-        if not base.startswith('lib'):
-            continue
-        if not base.endswith('.so') and '.so.' not in base:
-            continue
-
-        source = os.path.join(source_dir, base)
-        if os.path.islink(source):
-            continue
-        copy_library(source, base)
-
-    # Same for Python extension modules.  However, Android is strict about
-    # library naming, so we have a special naming scheme for these, in
-    # conjunction with a custom import hook to find these modules.
-    if not PkgSkip("PYTHON"):
-        suffix = GetExtensionSuffix()
-        source_dir = os.path.join(GetOutputDir(), "panda3d")
-        for base in os.listdir(source_dir):
-            if not base.endswith(suffix):
-                continue
-            modname = base[:-len(suffix)]
-            if '.' not in modname:
-                source = os.path.join(source_dir, base)
-                copy_library(source, "libpy.panda3d.{}.so".format(modname))
-
-        # Same for standard Python modules.
-        import _ctypes
-        source_dir = os.path.dirname(_ctypes.__file__)
-        for base in os.listdir(source_dir):
-            if not base.endswith('.so'):
-                continue
-            modname = base.partition('.')[0]
-            source = os.path.join(source_dir, base)
-            copy_library(source, "libpy.{}.so".format(modname))
-
-    def copy_python_tree(source_root, target_root):
-        for source_dir, dirs, files in os.walk(source_root):
-            if 'site-packages' in dirs:
-                dirs.remove('site-packages')
-
-            if not any(base.endswith('.py') for base in files):
-                continue
-
-            target_dir = os.path.join(target_root, os.path.relpath(source_dir, source_root))
-            target_dir = os.path.normpath(target_dir)
-            os.makedirs(target_dir, 0o755)
-
-            for base in files:
-                if base.endswith('.py'):
-                    target = os.path.join(target_dir, base)
-                    shutil.copy(os.path.join(source_dir, base), target)
-
-    # Copy the Python standard library to the .apk as well.
-    from distutils.sysconfig import get_python_lib
-    stdlib_source = get_python_lib(False, True)
-    stdlib_target = os.path.join("apkroot", "lib", "python{0}.{1}".format(*sys.version_info))
-    copy_python_tree(stdlib_source, stdlib_target)
-
-    # But also copy over our custom site.py.
-    shutil.copy("panda/src/android/site.py", os.path.join(stdlib_target, "site.py"))
-
-    # And now make a site-packages directory containing our direct/panda3d/pandac modules.
-    for tree in "panda3d", "direct", "pandac":
-        copy_python_tree(os.path.join(GetOutputDir(), tree), os.path.join(stdlib_target, "site-packages", tree))
-
-    # Copy the models and config files to the virtual assets filesystem.
-    oscmd("mkdir apkroot/assets")
-    oscmd("cp -R %s apkroot/assets/models" % (os.path.join(GetOutputDir(), "models")))
-    oscmd("cp -R %s apkroot/assets/etc" % (os.path.join(GetOutputDir(), "etc")))
-
-    # Make an empty res folder.  It's needed for the apk to be installable, apparently.
-    oscmd("mkdir apkroot/res")
-
-    # Now package up the application
-    oscmd("cp panda/src/android/pview_manifest.xml apkroot/AndroidManifest.xml")
-    aapt_cmd = "aapt package"
-    aapt_cmd += " -F %s" % (apk_unaligned)
-    aapt_cmd += " -M apkroot/AndroidManifest.xml"
-    aapt_cmd += " -A apkroot/assets -S apkroot/res"
-    aapt_cmd += " -I $PREFIX/share/aapt/android.jar"
-    oscmd(aapt_cmd)
-
-    # And add all the libraries to it.
-    oscmd("cd apkroot && aapt add ../%s classes.dex" % (apk_unaligned))
-    for path, dirs, files in os.walk('apkroot/lib'):
-        if files:
-            rel = os.path.relpath(path, 'apkroot')
-            oscmd("cd apkroot && aapt add ../%s %s/*" % (apk_unaligned, rel))
-
-    # Now align the .apk, which is necessary for Android to load it.
-    oscmd("zipalign -v -p 4 %s %s" % (apk_unaligned, apk_unsigned))
-
-    # Finally, sign it using a debug key.  This is generated if it doesn't exist.
-    oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned))
-
-    # Clean up.
-    oscmd("rm -rf apkroot")
-    os.unlink(apk_unaligned)
-    os.unlink(apk_unsigned)
-
-try:
-    if INSTALLER:
-        ProgressOutput(100.0, "Building installer")
-        target = GetTarget()
-        if target == 'windows':
-            fn = "Panda3D-"
-            dir = "Panda3D-" + VERSION
-
-            if RUNTIME:
-                fn += "Runtime-"
-                title = "Panda3D " + VERSION
-            else:
-                title = "Panda3D SDK " + VERSION
-
-            fn += VERSION
-
-            if not RUNTIME and SDK["PYTHONVERSION"] != "python2.7":
-                fn += '-py' + SDK["PYTHONVERSION"][6:]
-
-            if GetOptimize() <= 2:
-                fn += "-dbg"
-            if GetTargetArch() == 'x64':
-                fn += '-x64'
-                dir += '-x64'
-
-            MakeInstallerNSIS(fn + '.exe', title, 'C:\\' + dir)
-            if not RUNTIME:
-                MakeDebugSymbolArchive(fn + '-pdb.zip', dir)
-        elif (target == 'linux'):
-            MakeInstallerLinux()
-        elif (target == 'darwin'):
-            MakeInstallerOSX()
-        elif (target == 'freebsd'):
-            MakeInstallerFreeBSD()
-        elif (target == 'android'):
-            MakeInstallerAndroid()
-        else:
-            exit("Do not know how to make an installer for this platform")
-
-    if WHEEL:
-        ProgressOutput(100.0, "Building wheel")
-        from makewheel import makewheel
-        makewheel(WHLVERSION, GetOutputDir())
-finally:
-    SaveDependencyCache()
+if INSTALLER:
+    ProgressOutput(100.0, "Building installer")
+    from makepackage import MakeInstaller
+    MakeInstaller(version=VERSION, outputdir=GetOutputDir(),
+                  optimize=GetOptimize(), compressor=COMPRESSOR,
+                  debversion=DEBVERSION, rpmrelease=RPMRELEASE,
+                  runtime=RUNTIME)
+
+if WHEEL:
+    ProgressOutput(100.0, "Building wheel")
+    from makewheel import makewheel
+    makewheel(WHLVERSION, GetOutputDir())
 
 ##########################################################################################
 #

+ 0 - 19
makepanda/makepanda.vcproj

@@ -3578,25 +3578,6 @@
 				<File RelativePath="..\panda\src\net\datagram_ui.cxx"></File>
 				<File RelativePath="..\panda\src\net\netAddress.cxx"></File>
 			</Filter>
-			<Filter Name="awesomium">
-				<File RelativePath="..\panda\src\awesomium\WebBrowserTexture.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\awesomium_includes.h"></File>
-				<File RelativePath="..\panda\src\awesomium\pandaawesomium_composite1.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebViewListener.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebViewListener.h"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebCore.h"></File>
-				<File RelativePath="..\panda\src\awesomium\WebBrowserTexture.h"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebCore.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\AwMouseAndKeyboard.h"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebViewListener.I"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebView.h"></File>
-				<File RelativePath="..\panda\src\awesomium\config_awesomium.h"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebCore.I"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebView.I"></File>
-				<File RelativePath="..\panda\src\awesomium\awWebView.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\AwMouseAndKeyboard.cxx"></File>
-				<File RelativePath="..\panda\src\awesomium\config_awesomium.cxx"></File>
-			</Filter>
 			<Filter Name="movies">
 				<File RelativePath="..\panda\src\movies\ffmpegVideoCursor.h"></File>
 				<File RelativePath="..\panda\src\movies\movies_composite.cxx"></File>

+ 1 - 1
panda/src/audiotraits/openalAudioSound.cxx

@@ -44,7 +44,7 @@ OpenALAudioSound(OpenALAudioManager* manager,
   _loops_completed(0),
   _source(0),
   _manager(manager),
-  _volume(manager->get_volume()),
+  _volume(1.0f),
   _balance(0),
   _play_rate(1.0),
   _positional(positional),

+ 0 - 47
panda/src/awesomium/AwMouseAndKeyboard.cxx

@@ -1,47 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file AwMouseAndKeyboard.cxx
- * @author Bei Yang
- * @date 2010-03
- */
-
-#include "config_awesomium.h"
-#include "AwMouseAndKeyboard.h"
-#include "dataNodeTransmit.h"
-
-TypeHandle AwMouseAndKeyboard::_type_handle;
-
-AwMouseAndKeyboard::AwMouseAndKeyboard(const std::string &name):
-DataNode(name)
-{
-  _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
-  _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
-}
-
-
-void AwMouseAndKeyboard::do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, DataNodeTransmit &output){
-
-  if (input.has_data(_button_events_input)) {
-    const ButtonEventList *button_events;
-    DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
-
-    int num_events = button_events->get_num_events();
-    for (int i = 0; i < num_events; i++) {
-      const ButtonEvent &be = button_events->get_event(i);
-      std::string event_name = be._button.get_name();
-      printf("Button Event! : %s with code %i and index %i ", event_name.c_str(), be._keycode, be._button.get_index());
-      if(be._type == ButtonEvent::T_down) printf("down");
-      if(be._type == ButtonEvent::T_repeat) printf("repeat");
-      if(be._type == ButtonEvent::T_up) printf("up");
-      if(be._type == ButtonEvent::T_resume_down) printf("T_resume_down");
-      printf("\n");
-    }
-  }
-
-}

+ 0 - 61
panda/src/awesomium/AwMouseAndKeyboard.h

@@ -1,61 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file AwMouseAndKeyboard.h
- * @author rurbino
- * @date 2009-10-12
- */
-
-#ifndef AWWEBKEYBOARDMOUSE_H
-#define AWWEBKEYBOARDMOUSE_H
-
-#include "pandabase.h"
-#include "typedReferenceCount.h"
-#include "luse.h"
-
-#include "mouseAndKeyboard.h"
-
-
-/**
- * Thin wrappings arround WebCore.h
- */
-class EXPCL_PANDAAWESOMIUM AwMouseAndKeyboard : public DataNode {
-// member data data
-protected:
-  // inputs adn output indices... initialized in constructor
-  int _button_events_input;
-  int _button_events_output;
-
-PUBLISHED:
-  AwMouseAndKeyboard(const std::string &name);
-
-protected:
-  // Inherited from DataNode
-  virtual void do_transmit_data(DataGraphTraverser *trav,
-                                const DataNodeTransmit &input,
-                                DataNodeTransmit &output);
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    MouseAndKeyboard::init_type();
-    register_type(_type_handle, "AwMouseAndKeyboard",
-                  DataNode::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#endif

+ 0 - 8
panda/src/awesomium/ReadMe.txt

@@ -1,8 +0,0 @@
-See http://www.sirikata.com/wiki/index.php?title=Compiling_Awesomium
-
-But the Chromium revision 22725.
-The awesomium git repository used is at: http://github.com/pathorn/awesomium/network
-The version of awesomium is from the master August 7 checkin, tree fc3239b4f49031285682cb5d78256d56e9001b66
-
-Any method that had a wstring in the parameter, a second method was created which just accepts all std::string. This fixes the VC7 - VC9 linker error.
-

+ 0 - 194
panda/src/awesomium/WebBrowserTexture.cxx

@@ -1,194 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file WebBrowserTexture.cxx
- * @author bei yang
- * @date 2010-03
- */
-
-#include "config_awesomium.h"
-#include "WebBrowserTexture.h"
-
-TypeHandle WebBrowserTexture::_type_handle;
-
-/**
- * Copy constructor for web browser texture.  The behavior of copying a
- * webtexture is that will be the same as a standard texture copy.  However,
- * the content will remain the system until set_web_view is called.
- */
-WebBrowserTexture::WebBrowserTexture(const WebBrowserTexture &copy):
-Texture(copy)
-{
-    // this kind of assumes that the previous texture was initialized properly
-    _aw_web_view = copy._aw_web_view;
-    _update_active = copy._update_active;
-    _flip_texture_active = copy._flip_texture_active;
-}
-
-/**
- * This initializes a web browser texture with the given AwWebView class.
- */
-WebBrowserTexture::WebBrowserTexture(const std::string &name, AwWebView* aw_web_view):
-Texture(name),
-_update_active(true),
-_flip_texture_active(false)
-{
-    set_web_view(aw_web_view);
-    set_minfilter(FT_linear);
-    set_magfilter(FT_linear);
-
-}
-
-/**
- * Standard destructor... doesn't do anything.  All destructing happens in
- * parent texture class.
- */
-WebBrowserTexture::~WebBrowserTexture()
-{
-    // do nothing
-}
-
-
-/**
- * Standard destructor... doesn't do anything.  All destructing happens in
- * parent texture class.
- */
-bool WebBrowserTexture::get_keep_ram_image() const {
-    return true;
-}
-
-/**
- * A WebBrowserTexture must always keep its ram image.  This is essentially a
- * sub.
- */
-void WebBrowserTexture::do_reload_ram_image() {
-    // A MovieTexture should never dump its RAM image.  Therefore, this is not
-    // needed.
-}
-
-/**
- * Should be overridden by derived classes to return true if cull_callback()
- * has been defined.  Otherwise, returns false to indicate cull_callback()
- * does not need to be called for this node during the cull traversal.
- *
- * This one returns true because it uses the cull traverser method to do the
- * texture udpate.
- */
-bool WebBrowserTexture::has_cull_callback() const {
-    return true;
-}
-
-/**
- * Sets the internal AwWebView of this texture.  After calling this, the
- * texture will automatically set it's width and height to match the AwWebView
- * at the next time it is culled and rendered.
- */
-void WebBrowserTexture::set_web_view(AwWebView* aw_web_view){
-    _aw_web_view = aw_web_view;
-}
-
-
-/**
- * Gets the current internal AwWebView of this texture.
- */
-AwWebView* WebBrowserTexture::get_web_view() const{
-    return _aw_web_view;
-}
-
-
-/**
- * Gives the ability to toggle updating this texture or not.  This can be
- * disabled to improve performance so that only the one that needs to be
- * active is active.
- */
-void WebBrowserTexture::set_update_active(bool active_flag){
-    _update_active = active_flag;
-}
-
-
-/**
- * Gets whether or not this texture is updating itself every time it is
- * rendered.
- */
-bool WebBrowserTexture::get_update_active() const{
-    return _update_active;
-}
-
-
-/**
- * This toggles on/off automatic flipping of the of the texture at a source
- * level.  Awesomium renders things that are flipped vertically.  This enables
- * automatic flipping of that.
- *
- * Since it is doing byte manipulation, this can get rather slow.  Turning
- * this on should be avoided.  Instead, flipping should be taken care of via
- * UV coordinates or shaders.
- */
-void WebBrowserTexture::set_flip_texture_active(bool active_flag){
-    _flip_texture_active = active_flag;
-}
-
-/**
- * Returns whether automatic texture flipping is enabled.
- */
-bool WebBrowserTexture::get_flip_texture_active() const {
-    return _flip_texture_active;
-}
-
-
-/**
- * This function will be called during the cull traversal to update the
- * WebBrowserTexture.  This method calls the render method of AwWebView but
- * does not call the update method of AwWebCore.
- */
-bool WebBrowserTexture::cull_callback(CullTraverser *trav, const CullTraverserData &data) const{
-    // see if we are in a state where udpates can happen.  else just return
-    if( !_update_active ) return true;
-    if( _aw_web_view == nullptr ) return true;
-
-    // do we even need to update?
-    if( !_aw_web_view->is_dirty() ) return true;
-
-    // see if we're the same size, if not we need to make sure this texture
-    // matches the webview
-    if( _aw_web_view->get_width() != get_x_size() || _aw_web_view->get_height() != get_y_size() || get_texture_type() != TT_2d_texture){
-        // these casts are so dirty especially when the method itself is
-        // labled as const.  Really Texture::cull_callback should be not const
-        // first clean up
-        ((WebBrowserTexture*)this)->clear_ram_mipmap_images();
-        ((WebBrowserTexture*)this)->clear_ram_image();
-        // now set up the texture again
-        ((WebBrowserTexture*)this)->setup_2d_texture( _aw_web_view->get_width(), _aw_web_view->get_height(), T_unsigned_byte, F_rgba );
-        // should be good to go at this point
-    }
-
-    // get the pointer
-    PTA_uchar ram_image = ((WebBrowserTexture*)this)->modify_ram_image();
-    unsigned char* cp_data = ram_image.p();
-    // render it
-    _aw_web_view->render((void*)cp_data, get_x_size()*4, 4);
-
-    if(_flip_texture_active){
-        // flips the texture around... this is super slow.  Really this should
-        // never be enabled.  However beginners might find this useful
-        size_t width = get_x_size();
-        size_t height = get_y_size();
-        for(size_t i=0; i < height/2; i++){
-            for(size_t j=0; j < width; j++){
-                unsigned char tmp[4];
-                size_t a_pos = j+width*i;
-                size_t b_pos = j + width*(height-i-1);
-                memcpy(tmp,&cp_data[4*a_pos], 4); //tmp = a
-                memcpy(&cp_data[4*a_pos], &cp_data[4*b_pos], 4); //a = b
-                memcpy(&cp_data[4*b_pos], tmp, 4); //b = tmp
-            }
-        }
-    }
-    // success
-    return true;
-}

+ 0 - 77
panda/src/awesomium/WebBrowserTexture.h

@@ -1,77 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file WebBrowserTexture.h
- * @author Bei Yang
- * @date 2010-08-03
- */
-
-#ifndef WebBrowserTexture_H
-#define WebBrowserTexture_H
-
-#include "pandabase.h"
-#include "texture.h"
-#include "awWebView.h"
-
-
-/**
- * A Wrapper class for Awesomium webview.  This implements most of Awesomium's
- * features and updates on the cull_traverser callback much much like a movie
- * texture.
- *
- * The use of class means that you will have to follow Awesomium license
- * agreement give below http://www.khrona.com/products/awesomium/licensing
- */
-class EXPCL_PANDAAWESOMIUM WebBrowserTexture : public Texture {
-protected:
-    AwWebView* _aw_web_view;
-    bool _update_active;
-    bool _flip_texture_active;
-
-// Constructors & Destructors ------------
-private:
-    WebBrowserTexture(const WebBrowserTexture &copy);
-PUBLISHED:
-    WebBrowserTexture(const std::string &name, AwWebView* aw_web_view = nullptr);
-    virtual ~WebBrowserTexture();
-
-
-// methods --------------
-protected:
-    bool get_keep_ram_image() const;
-    void do_reload_ram_image();
-public:
-    virtual bool has_cull_callback() const;
-    virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const;
-PUBLISHED:
-    void set_web_view(AwWebView* aw_web_view);
-    AwWebView* get_web_view() const;
-    void set_update_active(bool active_flag);
-    bool get_update_active() const;
-    void set_flip_texture_active(bool active_flag);
-    bool get_flip_texture_active() const;
-
-// Type handles ----------------
-public:
-    static TypeHandle get_class_type() {
-        return _type_handle;
-    }
-    static void init_type() {
-        Texture::init_type();
-        register_type(_type_handle, "WebBrowserTexture",
-            Texture::get_class_type());
-    }
-    virtual TypeHandle get_type() const {
-        return get_class_type();
-    }
-    virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-    static TypeHandle _type_handle;
-};
-#endif

+ 0 - 48
panda/src/awesomium/awWebCore.I

@@ -1,48 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebCore.I
- * @author rurbino
- * @date 2009-10-12
- */
-
-INLINE void AwWebCore::
-setBaseDirectory(const std::string& baseDirectory) {
-  WebCore::setBaseDirectory(baseDirectory);
-}
-
-INLINE void AwWebCore::
-setCustomResponsePage(int statusCode, const std::string& filePath) {
-  WebCore::setCustomResponsePage(statusCode, filePath);
-}
-
-INLINE void AwWebCore::
-update() {
-  WebCore::update();
-}
-
-INLINE const std::string& AwWebCore::
-getBaseDirectory() const {
-  return WebCore::getBaseDirectory();
-}
-
-INLINE bool AwWebCore::
-arePluginsEnabled() const {
-  return WebCore::arePluginsEnabled();
-}
-
-
-INLINE void AwWebCore::
-pause(){
-  WebCore::pause();
-}
-
-INLINE void AwWebCore::
-resume() {
-  WebCore::resume();
-}

+ 0 - 56
panda/src/awesomium/awWebCore.cxx

@@ -1,56 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebCore.cxx
- * @author rurbino
- * @date 2009-10-12
- */
-
-#include "config_awesomium.h"
-#include "awWebCore.h"
-
-#include <WebCore.h>
-
-TypeHandle AwWebCore::_type_handle;
-
-AwWebCore::
-AwWebCore(AwWebCore::LogLevel level, bool enablePlugins , AwWebCore::PixelFormat pixelFormat)
-#ifndef CPPPARSER
-:
-  WebCore(static_cast<Awesomium::LogLevel>(level), enablePlugins, static_cast<Awesomium::PixelFormat>(pixelFormat))
-#endif
-  {
-  awesomium_cat.info() << "constructing webcore\n";
-}
-
-AwWebCore::
-~AwWebCore() {
-  awesomium_cat.info() << "destructor webcore\n";
-}
-
-Awesomium::WebCore& AwWebCore::
-Get() {
-  return WebCore::Get();
-}
-
-Awesomium::WebCore* AwWebCore::
-GetPointer() {
-  return WebCore::GetPointer();
-}
-
-AwWebView *  AwWebCore::
-createWebView(int width, int height, bool isTransparent , bool enableAsyncRendering , int maxAsyncRenderPerSec ) {
-  Awesomium::WebView * newView = WebCore::createWebView(width, height, isTransparent, enableAsyncRendering, maxAsyncRenderPerSec);
-  AwWebView * result = new AwWebView(newView);
-  return result;
-}
-
-AwWebCore::PixelFormat AwWebCore::
-getPixelFormat() const {
-  return ( static_cast<AwWebCore::PixelFormat>( WebCore::getPixelFormat()) );
-}

+ 0 - 94
panda/src/awesomium/awWebCore.h

@@ -1,94 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebCore.h
- * @author rurbino
- * @date 2009-10-12
- */
-
-#ifndef AWWEBCORE_H
-#define AWWEBCORE_H
-
-#include "pandabase.h"
-#include "typedReferenceCount.h"
-#include "luse.h"
-
-#include "awesomium_includes.h"
-
-class AwWebView;
-/**
- * Thin wrappings arround WebCore.h
- */
-class EXPCL_PANDAAWESOMIUM AwWebCore : public TypedReferenceCount, public Awesomium::WebCore {
-PUBLISHED:
-  /**
-  * An enumeration of the three verbosity settings for the Awesomium Log.
-  */
-  enum LogLevel
-  {
-    LOG_NONE ,      // No log is created
-    LOG_NORMAL ,        // Logs only errors
-    LOG_VERBOSE         // Logs everything
-  };
-
-  /**
-  * An enumeration of the two output pixel formats that WebView::render will use.
-  */
-  enum PixelFormat
-  {
-    PF_BGRA,    // BGRA byte ordering [Blue, Green, Red, Alpha]
-    PF_RGBA     // RGBA byte ordering [Red, Green, Blue, Alpha]
-  };
-
-  AwWebCore(LogLevel level = LOG_NORMAL, bool enablePlugins = true, PixelFormat pixelFormat = PF_BGRA);
-
-  virtual ~AwWebCore();
-
-  static Awesomium::WebCore& Get();
-
-  static Awesomium::WebCore* GetPointer();
-
-  INLINE void setBaseDirectory(const std::string& baseDirectory);
-
-  AwWebView * createWebView(int width, int height, bool isTransparent = false, bool enableAsyncRendering = false, int maxAsyncRenderPerSec = 70);
-
-  INLINE void setCustomResponsePage(int statusCode, const std::string& filePath);
-
-  INLINE void update();
-
-  INLINE const std::string& getBaseDirectory() const;
-
-  AwWebCore::PixelFormat getPixelFormat() const;
-
-  INLINE bool arePluginsEnabled() const;
-
-  INLINE void pause();
-
-  INLINE void resume();
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedReferenceCount::init_type();
-    register_type(_type_handle, "AwWebCore",
-                  TypedReferenceCount::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "awWebCore.I"
-
-#endif

+ 0 - 82
panda/src/awesomium/awWebView.I

@@ -1,82 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebView.I
- * @author rurbino
- * @date 2009-10-12
- */
-
-INLINE void AwWebView::
-destroy(void)
-{
-  _myWebView->destroy();
-}
-
-
-INLINE void AwWebView::
-setListener(Awesomium::WebViewListener *  listener) {
-  _myWebView->setListener(listener);
-}
-
-INLINE Awesomium::WebViewListener* AwWebView::
-getListener() {
-  return _myWebView->getListener();
-}
-
-INLINE void AwWebView::
-goToHistoryOffset(int offset) {
-  _myWebView->goToHistoryOffset(offset);
-}
-
-INLINE void AwWebView::
-executeJavascript2(const std::string& javascript, const std::string& frameName ) {
-  _myWebView->executeJavascript2(javascript, frameName);
-}
-
-INLINE Awesomium::FutureJSValue AwWebView::
-executeJavascriptWithResult2(const std::string& javascript, const std::string& frameName ) {
-  return _myWebView->executeJavascriptWithResult2(javascript, frameName);
-}
-
-INLINE void AwWebView::
-setProperty(const std::string& name, const Awesomium::JSValue& value) {
-  _myWebView->setProperty(name, value);
-}
-
-INLINE void AwWebView::
-setCallback(const std::string& name) {
-  _myWebView->setCallback(name);
-}
-
-INLINE bool AwWebView::
-isDirty() {
-  return _myWebView->isDirty();
-}
-
-INLINE void AwWebView::
-render( size_t  destination, int destRowSpan, int destDepth)
-{
-  _myWebView->render( reinterpret_cast<unsigned char *>(destination), destRowSpan, destDepth, 0);
-}
-
-
-
-INLINE void AwWebView::
-injectMouseUp(AwWebView::MouseButton button) {
-  _myWebView->injectMouseUp(static_cast<Awesomium::MouseButton>(button));
-}
-
-INLINE void AwWebView::
-injectMouseWheelXY(int scrollAmountX, int scrollAmountY){
-  _myWebView->injectMouseWheelXY(scrollAmountX, scrollAmountY);
-}
-
-INLINE void AwWebView::
-injectKeyEvent(bool press, int modifiers, int windowsCode, int nativeCode) {
-  _myWebView->injectKeyEvent(press, modifiers, windowsCode, nativeCode);
-}

+ 0 - 74
panda/src/awesomium/awWebView.cxx

@@ -1,74 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebView.cxx
- * @author rurbino
- * @date 2009-10-12
- */
-
-#include "config_awesomium.h"
-#include "awWebView.h"
-
-TypeHandle AwWebView::_type_handle;
-
-AwWebView::
-AwWebView(Awesomium::WebView * webViewPtr)  {
-  _myWebView = webViewPtr;
-
-}
-
-AwWebView::
-~AwWebView() {
-}
-
-
-void AwWebView::
-loadURL2(const std::string& url, const std::string& frameName , const std::string& username , const std::string& password )
-{
-  _myWebView->loadURL2(url, frameName, username, password);
-
-}
-
-void AwWebView::
-loadHTML2(const std::string& html, const std::string& frameName )
-{
-  _myWebView->loadHTML2(html, frameName);
-}
-
-
-void AwWebView::
-loadFile2(const std::string& file, const std::string& frameName )
-{
-  _myWebView->loadFile2(file, frameName);
-}
-
-
-void AwWebView::
-render(size_t destination, int destRowSpan, int destDepth, AwWebView::Rect * renderedRect) {
-  if (renderedRect) {
-    Awesomium::Rect rect(renderedRect->x, renderedRect->y, renderedRect->width, renderedRect->height);
-    _myWebView->Awesomium::WebView::render( reinterpret_cast<unsigned char *>(destination), destRowSpan, destDepth, &rect);
-  }
-  else
-  {
-    AwWebView::render(destination, destRowSpan, destDepth, 0);
-  }
-}
-
-void AwWebView::
-injectMouseDown(AwWebView::MouseButton button) {
-  awesomium_cat.debug() <<"got mouse down " << button << "\n";
-  _myWebView->injectMouseDown(static_cast<Awesomium::MouseButton>(button));
-}
-
-
-void AwWebView::
-injectMouseMove(int x, int y) {
-  // awesomium_cat.debug() <<"got mouse move " << x << " " << y << "\n";
-  _myWebView->injectMouseMove(x,y);
-}

+ 0 - 131
panda/src/awesomium/awWebView.h

@@ -1,131 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebView.h
- * @author rurbino
- * @date 2009-10-12
- */
-
-#ifndef AWWEBVIEW_H
-#define AWWEBVIEW_H
-
-#include "pandabase.h"
-#include "typedReferenceCount.h"
-#include "luse.h"
-
-#include "awesomium_includes.h"
-
-class WebViewListener;
-
-/**
- * Thin bindings, wraps a WebView * returned from WebCore.createWebView
- */
-class EXPCL_PANDAAWESOMIUM AwWebView : public TypedReferenceCount{
-PUBLISHED:
-
-  /**
-  * Mouse button enumerations, used with WebView::injectMouseDown
-  * and WebView::injectMouseUp
-  */
-  enum MouseButton {
-    LEFT_MOUSE_BTN,
-    MIDDLE_MOUSE_BTN,
-    RIGHT_MOUSE_BTN
-  };
-
-  /**
-   * A simple rectangle class, used with WebView::render
-   */
-  struct Rect {
-    int x, y, width, height;
-
-    Rect();
-    Rect(int x, int y, int width, int height);
-    bool isEmpty() const;
-  };
-
-
-PUBLISHED:
-  AwWebView(Awesomium::WebView * webView);
-
-  virtual ~AwWebView();
-
-  INLINE void destroy(void);
-
-  INLINE void setListener(Awesomium::WebViewListener * listener);
-
-  INLINE Awesomium::WebViewListener* getListener();
-
-  // VC7 linker doesn't like wstring from VS2008, hence using the all regular
-  // string version
-  void loadURL2(const std::string& url, const std::string& frameName ="", const std::string& username="" , const std::string& password="");
-
-  // VC7 linker doesn't like wstring from VS2008, hence using the all regular
-  // string version
-  void loadHTML2(const std::string& html, const std::string& frameName = "");
-
-  // VC7 linker doesn't like wstring from VS2008, hence using the all regular
-  // string version
-  void loadFile2(const std::string& file, const std::string& frameName = "" );
-
-  INLINE void goToHistoryOffset(int offset);
-
-  // VC7 linker doesn't like wstring from VS2008, hence using the all regular
-  // string version
-  INLINE void executeJavascript2(const std::string& javascript, const std::string& frameName = "" );
-
-  INLINE Awesomium::FutureJSValue executeJavascriptWithResult2(const std::string& javascript, const std::string& frameName = "");
-
-  INLINE void setProperty(const std::string& name, const Awesomium::JSValue& value);
-
-  INLINE void setCallback(const std::string& name);
-
-  INLINE bool isDirty();
-
-  INLINE void render(size_t destination, int destRowSpan, int destDepth);
-
-  void render(size_t destination, int destRowSpan, int destDepth, AwWebView::Rect * renderedRect);
-
-  void injectMouseMove(int x, int y);
-
-  void injectMouseDown(AwWebView::MouseButton button);
-
-  INLINE void injectMouseUp(AwWebView::MouseButton button);
-
-  INLINE void injectMouseWheelXY(int scrollAmountX, int scrollAmountY);
-
-  INLINE void injectMouseWheel(int scrollAmountY) {
-    injectMouseWheelXY(0, scrollAmountY);
-  }
-
-  INLINE void injectKeyEvent(bool press, int modifiers, int windowsCode, int nativeCode=0);
-
-private:
-  Awesomium::WebView * _myWebView;
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedReferenceCount::init_type();
-    register_type(_type_handle, "AwWebView",
-                  TypedReferenceCount::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "awWebView.I"
-
-#endif

+ 0 - 12
panda/src/awesomium/awWebViewListener.I

@@ -1,12 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebViewListener.I
- * @author rurbino
- * @date 2009-10-12
- */

+ 0 - 80
panda/src/awesomium/awWebViewListener.cxx

@@ -1,80 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebViewListener.cxx
- * @author rurbino
- * @date 2009-10-12
- */
-
-#include "config_awesomium.h"
-#include "awWebViewListener.h"
-
-TypeHandle AwWebViewListener::_type_handle;
-
-AwWebViewListener::
-AwWebViewListener()  {
-  awesomium_cat.info() << "constructing WebViewListner" ;
-}
-
-void AwWebViewListener::onBeginNavigation(const std::string& url, const std::wstring& frameName){
-}
-
-void AwWebViewListener::onBeginLoading(const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType) {
-  awesomium_cat.info() << "onBeginLoading" ;
-}
-
-    /**
-    * This event is fired when all loads have finished for a WebView.
-    */
-void AwWebViewListener::onFinishLoading() {
-}
-
-    /**
-    * This event is fired when a Client callback has been invoked via Javascript from a page.
-    *
-    * @param    name    The name of the client callback that was invoked (specifically, "Client._this_name_here_(...)").
-    *
-    * @param    args    The arguments passed to the callback.
-    */
-void AwWebViewListener::onCallback(const std::string& name, const Awesomium::JSArguments& args) {
-}
-
-    /**
-    * This event is fired when a page title is received.
-    *
-    * @param    title   The page title.
-    *
-    * @param    frameName   The name of the frame that this event originated from.
-    */
-void AwWebViewListener::onReceiveTitle(const std::wstring& title, const std::wstring& frameName) {
-}
-
-    /**
-    * This event is fired when a tooltip has changed state.
-    *
-    * @param    tooltip     The tooltip text (or, is an empty string when the tooltip should disappear).
-    */
-void AwWebViewListener::onChangeTooltip(const std::wstring& tooltip) {
-}
-
-    /**
-    * This event is fired when keyboard focus has changed.
-    *
-    * @param    isFocused   Whether or not the keyboard is currently focused.
-    */
-void AwWebViewListener::onChangeKeyboardFocus(bool isFocused) {
-}
-
-    /**
-    * This event is fired when the target URL has changed. This is usually the result of
-    * hovering over a link on the page.
-    *
-    * @param    url The updated target URL (or empty if the target URL is cleared).
-    */
-void AwWebViewListener::onChangeTargetURL(const std::string& url) {
-}

+ 0 - 123
panda/src/awesomium/awWebViewListener.h

@@ -1,123 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awWebViewListener.h
- * @author rurbino
- * @date 2009-10-12
- */
-
-#ifndef AWWEBVIEWLISTENER_H
-#define AWWEBVIEWLISTENER_H
-
-#include "pandabase.h"
-#include "typedReferenceCount.h"
-#include "luse.h"
-
-#include "awesomium_includes.h"
-
-/**
- * Thin bindings, wraps a WebViewListener
- */
-class EXPCL_PANDAAWESOMIUM AwWebViewListener : public TypedReferenceCount, public Awesomium::WebCore {
-PUBLISHED:
-
-
-PUBLISHED:
-        AwWebViewListener();
-
-        virtual ~AwWebViewListener() {}
-
-    /**
-    * This event is fired when a WebView begins navigating to a new URL.
-    *
-    * @param    url     The URL that is being navigated to.
-    *
-    * @param    frameName   The name of the frame that this event originated from.
-    */
-    void onBeginNavigation(const std::string& url, const std::wstring& frameName) ;
-
-    /**
-    * This event is fired when a WebView begins to actually receive data from a server.
-    *
-    * @param    url     The URL of the frame that is being loaded.
-    *
-    * @param    frameName   The name of the frame that this event originated from.
-    *
-    * @param    statusCode  The HTTP status code returned by the server.
-    *
-    * @param    mimeType    The mime-type of the content that is being loaded.
-    */
-        void onBeginLoading(const std::string& url, const std::wstring& frameName, int statusCode, const std::wstring& mimeType);
-
-    /**
-    * This event is fired when all loads have finished for a WebView.
-    */
-        void onFinishLoading();
-
-    /**
-    * This event is fired when a Client callback has been invoked via Javascript from a page.
-    *
-    * @param    name    The name of the client callback that was invoked (specifically, "Client._this_name_here_(...)").
-    *
-    * @param    args    The arguments passed to the callback.
-    */
-  void onCallback(const std::string& name, const Awesomium::JSArguments& args);
-
-    /**
-    * This event is fired when a page title is received.
-    *
-    * @param    title   The page title.
-    *
-    * @param    frameName   The name of the frame that this event originated from.
-    */
-  void onReceiveTitle(const std::wstring& title, const std::wstring& frameName) ;
-
-    /**
-    * This event is fired when a tooltip has changed state.
-    *
-    * @param    tooltip     The tooltip text (or, is an empty string when the tooltip should disappear).
-    */
-    void onChangeTooltip(const std::wstring& tooltip);
-
-    /**
-    * This event is fired when keyboard focus has changed.
-    *
-    * @param    isFocused   Whether or not the keyboard is currently focused.
-    */
-    void onChangeKeyboardFocus(bool isFocused) ;
-
-    /**
-    * This event is fired when the target URL has changed. This is usually the result of
-    * hovering over a link on the page.
-    *
-    * @param    url The updated target URL (or empty if the target URL is cleared).
-    */
-    void onChangeTargetURL(const std::string& url) ;
-
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedReferenceCount::init_type();
-    register_type(_type_handle, "AwWebViewListener",
-                  TypedReferenceCount::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-// #include "awWebViewListener.I"
-
-#endif

+ 0 - 21
panda/src/awesomium/awesomium_includes.h

@@ -1,21 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file awesomium_includes.h
- * @author rurbino
- * @date 2010-10-08
- */
-
-#ifndef _AWESOMIUM_INCLUDES_H_
-#define _AWESOMIUM_INCLUDES_H_
-
-#include <WebCore.h>
-#include <WebView.h>
-#include <WebViewListener.h>
-
-#endif

+ 0 - 51
panda/src/awesomium/config_awesomium.cxx

@@ -1,51 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file config_awesomium.cxx
- * @author rurbino
- * @date 2009-10-12
- */
-
-#include "config_awesomium.h"
-#include "awWebCore.h"
-#include "awWebView.h"
-#include "awWebViewListener.h"
-#include "dconfig.h"
-
-
-#if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_PANDAAWESOMIUM)
-  #error Buildsystem error: BUILDING_PANDAAWESOMIUM not defined
-#endif
-
-Configure(config_awesomium);
-NotifyCategoryDef(awesomium, "");
-
-
-ConfigureFn(config_awesomium) {
-  init_libawesomium();
-}
-
-/**
- * Initializes the library.  This must be called at least once before any of
- * the functions or classes in this library can be used.  Normally it will be
- * called by the static initializers and need not be called explicitly, but
- * special cases exist.
- */
-void
-init_libawesomium() {
-  static bool initialized = false;
-  if (initialized) {
-    return;
-  }
-  initialized = true;
-
-  AwWebCore::init_type();
-  AwWebView::init_type();
-  AwWebViewListener::init_type();
-
-}

+ 0 - 26
panda/src/awesomium/config_awesomium.h

@@ -1,26 +0,0 @@
-/**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University.  All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license.  You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file config_awesomium.h
- * @author rurbino
- * @date 2009-10-12
- */
-
-#ifndef CONFIG_AWESOMIUM_H
-#define CONFIG_AWESOMIUM_H
-
-#include "pandabase.h"
-#include "notifyCategoryProxy.h"
-
-#include "dconfig.h"
-
-NotifyCategoryDecl(awesomium, EXPCL_PANDAAWESOMIUM, EXPTP_PANDAAWESOMIUM);
-
-extern EXPCL_PANDAAWESOMIUM void init_libawesomium();
-
-#endif /* CONFIG_AWESOMIUM_H */

+ 0 - 4
panda/src/awesomium/pandaawesomium_composite1.cxx

@@ -1,4 +0,0 @@
-#include "config_awesomium.cxx"
-#include "awWebCore.cxx"
-#include "awWebView.cxx"
-#include "awWebViewListener.cxx"

+ 6 - 3
panda/src/bullet/bulletVehicle.cxx

@@ -235,10 +235,13 @@ void BulletVehicle::
 do_sync_b2p() {
 
   for (int i=0; i < _vehicle->getNumWheels(); i++) {
-    // synchronize the wheels with the (interpolated) chassis worldtransform
-    _vehicle->updateWheelTransform(i, true);
+    btWheelInfo &info = _vehicle->getWheelInfo(i);
 
-    btWheelInfo info = _vehicle->getWheelInfo(i);
+    // synchronize the wheels with the (interpolated) chassis worldtransform.
+    // It resets the m_isInContact flag, so restore that afterwards.
+    bool in_contact = info.m_raycastInfo.m_isInContact;
+    _vehicle->updateWheelTransform(i, true);
+    info.m_raycastInfo.m_isInContact = in_contact;
 
     PandaNode *node = (PandaNode *)info.m_clientInfo;
     if (node) {

+ 15 - 0
panda/src/cocoadisplay/cocoaPandaView.mm

@@ -26,6 +26,10 @@
   [self setCanDrawConcurrently:YES];
 #endif
 
+  // If a layer ends up becoming attached to the view, tell AppKit we'll manage
+  // the redrawing since we're doing things our own way.
+  self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawNever;
+
   cocoadisplay_cat.debug()
     << "Created CocoaPandaView " << self << " for GraphicsWindow " << window << "\n";
   _graphicsWindow = window;
@@ -167,4 +171,15 @@
 - (BOOL) isOpaque {
   return YES;
 }
+
+-(void)setLayer:(CALayer*)layer
+{
+    [super setLayer:layer];
+
+    // Starting in macOS 10.14, a CALayer will still be attached to a view even
+    // if `wantsLayer` is false. If we don't update the context now, only a
+    // black screen will be rendered until the context is updated some other
+    // way (like through a window resize event).
+    [_context update];
+}
 @end

+ 23 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -771,6 +771,28 @@ reset() {
     _supported_geom_rendering |= Geom::GR_point_sprite;
   }
 
+  // Determine whether we support wide lines (and how wide they can be).
+  {
+    GLfloat aliased_range[2] = {1.0f, 1.0f};
+    glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, aliased_range);
+
+    _max_line_width = aliased_range[1];
+
+#ifdef SUPPORT_FIXED_FUNCTION
+    if (has_fixed_function_pipeline()) {
+#ifndef OPENGLES
+      GLfloat range[2] = {1.0f, 1.0f};
+      glGetFloatv(GL_LINE_WIDTH_RANGE, range);
+      _max_line_width = std::max(_max_line_width, range[1]);
+#endif
+
+      GLfloat smooth_range[2] = {1.0f, 1.0f};
+      glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, smooth_range);
+      _max_line_width = std::max(_max_line_width, smooth_range[1]);
+    }
+#endif
+  }
+
 #ifdef OPENGLES_1
   // OpenGL ES 1.0 does not support primitive restart indices.
 
@@ -7352,7 +7374,7 @@ do_issue_render_mode() {
       GLCAT.spam() << "setting thickness to " << thickness << "\n";
     }
 
-    glLineWidth(thickness);
+    glLineWidth(std::min((GLfloat)thickness, _max_line_width));
 #ifndef OPENGLES_2
     glPointSize(thickness);
 #endif

+ 2 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -685,6 +685,8 @@ protected:
 #endif
 #endif
 
+  GLfloat _max_line_width;
+
 #ifdef HAVE_CG
   CGcontext _cg_context;
 #endif

+ 20 - 9
panda/src/gobj/geomPrimitive.cxx

@@ -538,15 +538,26 @@ offset_vertices(int offset, int begin_row, int end_row) {
 void GeomPrimitive::
 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
   Thread *current_thread = Thread::get_current_thread();
-  int num_vertices = get_num_vertices();
-  int dest_start = dest->get_num_rows();
-  int strip_cut_index = get_strip_cut_index();
-
-  dest->set_num_rows(dest_start + num_vertices);
-  for (int i = 0; i < num_vertices; ++i) {
-    int v = get_vertex(i);
-    nassertd(v != strip_cut_index) continue;
-    dest->copy_row_from(dest_start + i, source, v, current_thread);
+
+  int num_vertices, dest_start;
+  {
+    GeomPrimitivePipelineReader reader(this, current_thread);
+    num_vertices = reader.get_num_vertices();
+    int strip_cut_index = reader.get_strip_cut_index();
+
+    GeomVertexDataPipelineWriter data_writer(dest, false, current_thread);
+    data_writer.check_array_writers();
+    dest_start = data_writer.get_num_rows();
+    data_writer.set_num_rows(dest_start + num_vertices);
+
+    GeomVertexDataPipelineReader data_reader(source, current_thread);
+    data_reader.check_array_readers();
+
+    for (int i = 0; i < num_vertices; ++i) {
+      int v = reader.get_vertex(i);
+      nassertd(v != strip_cut_index) continue;
+      data_writer.copy_row_from(dest_start + i, data_reader, v);
+    }
   }
 
   set_nonindexed_vertices(dest_start, num_vertices);

+ 44 - 24
panda/src/gobj/geomVertexData.cxx

@@ -686,32 +686,13 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
 void GeomVertexData::
 copy_row_from(int dest_row, const GeomVertexData *source,
               int source_row, Thread *current_thread) {
-  const GeomVertexFormat *source_format = source->get_format();
-  const GeomVertexFormat *dest_format = get_format();
-  nassertv(source_format == dest_format);
-  nassertv(source_row >= 0 && source_row < source->get_num_rows());
-
-  if (dest_row >= get_num_rows()) {
-    // Implicitly add enough rows to get to the indicated row.
-    set_num_rows(dest_row + 1);
-  }
-
-  int num_arrays = source_format->get_num_arrays();
 
-  for (int i = 0; i < num_arrays; ++i) {
-    PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i);
-    unsigned char *dest_array_data = dest_handle->get_write_pointer();
-
-    CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i);
-    const unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
+  GeomVertexDataPipelineReader reader(source, current_thread);
+  reader.check_array_readers();
 
-    const GeomVertexArrayFormat *array_format = source_format->get_array(i);
-    int stride = array_format->get_stride();
-
-    memcpy(dest_array_data + stride * dest_row,
-           source_array_data + stride * source_row,
-           stride);
-  }
+  GeomVertexDataPipelineWriter writer(this, true, current_thread);
+  writer.check_array_writers();
+  writer.copy_row_from(dest_row, reader, source_row);
 }
 
 /**
@@ -2601,6 +2582,45 @@ set_array(size_t i, const GeomVertexArrayData *array) {
   }
 }
 
+/**
+ * Copies a single row of the data from the other array into the indicated row
+ * of this array.  In this case, the source format must exactly match the
+ * destination format.
+ *
+ * Don't call this in a downstream thread unless you don't mind it blowing
+ * away other changes you might have recently made in an upstream thread.
+ */
+void GeomVertexDataPipelineWriter::
+copy_row_from(int dest_row, const GeomVertexDataPipelineReader &source,
+              int source_row) {
+  const GeomVertexFormat *source_format = source.get_format();
+  const GeomVertexFormat *dest_format = get_format();
+  nassertv(source_format == dest_format);
+  nassertv(source_row >= 0 && source_row < source.get_num_rows());
+  nassertv(_got_array_writers);
+
+  if (dest_row >= get_num_rows()) {
+    // Implicitly add enough rows to get to the indicated row.
+    set_num_rows(dest_row + 1);
+  }
+
+  size_t num_arrays = source_format->get_num_arrays();
+  for (size_t i = 0; i < num_arrays; ++i) {
+    GeomVertexArrayDataHandle *dest_handle = get_array_writer(i);
+    unsigned char *dest_array_data = dest_handle->get_write_pointer();
+
+    const GeomVertexArrayDataHandle *source_array_handle = source.get_array_reader(i);
+    const unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
+
+    const GeomVertexArrayFormat *array_format = source_format->get_array(i);
+    int stride = array_format->get_stride();
+
+    memcpy(dest_array_data + stride * dest_row,
+           source_array_data + stride * source_row,
+           stride);
+  }
+}
+
 /**
  *
  */

+ 3 - 0
panda/src/gobj/geomVertexData.h

@@ -526,6 +526,9 @@ public:
   bool unclean_set_num_rows(int n);
   bool reserve_num_rows(int n);
 
+  void copy_row_from(int dest_row, const GeomVertexDataPipelineReader &source,
+                     int source_row);
+
 private:
   void make_array_writers();
   void delete_array_writers();

+ 0 - 8
panda/src/pandabase/pandasymbols.h

@@ -476,14 +476,6 @@
   #define EXPTP_PANDA_WGLDISPLAY IMPORT_TEMPL
 #endif
 
-#ifdef BUILDING_PANDAAWESOMIUM
-  #define EXPCL_PANDAAWESOMIUM EXPORT_CLASS
-  #define EXPTP_PANDAAWESOMIUM EXPORT_TEMPL
-#else
-  #define EXPCL_PANDAAWESOMIUM IMPORT_CLASS
-  #define EXPTP_PANDAAWESOMIUM IMPORT_TEMPL
-#endif
-
 #ifdef BUILDING_PANDAGL
   #define EXPCL_PANDAGL EXPORT_CLASS
   #define EXPTP_PANDAGL EXPORT_TEMPL

+ 9 - 0
panda/src/pgraph/billboardEffect.I

@@ -86,6 +86,15 @@ get_axial_rotate() const {
   return _axial_rotate;
 }
 
+/**
+ * Returns true if this billboard always appears at a fixed distance from the
+ * camera.
+ */
+INLINE bool BillboardEffect::
+get_fixed_depth() const {
+  return _fixed_depth;
+}
+
 /**
  * Returns the distance toward the camera (or the look_at_point) the billboard
  * is moved towards, after rotating.  This can be used to ensure the billboard

+ 40 - 5
panda/src/pgraph/billboardEffect.cxx

@@ -29,7 +29,7 @@ TypeHandle BillboardEffect::_type_handle;
 CPT(RenderEffect) BillboardEffect::
 make(const LVector3 &up_vector, bool eye_relative,
      bool axial_rotate, PN_stdfloat offset, const NodePath &look_at,
-     const LPoint3 &look_at_point) {
+     const LPoint3 &look_at_point, bool fixed_depth) {
   BillboardEffect *effect = new BillboardEffect;
   effect->_up_vector = up_vector;
   effect->_eye_relative = eye_relative;
@@ -37,6 +37,7 @@ make(const LVector3 &up_vector, bool eye_relative,
   effect->_offset = offset;
   effect->_look_at = look_at;
   effect->_look_at_point = look_at_point;
+  effect->_fixed_depth = fixed_depth;
   effect->_off = false;
   return return_new(effect);
 }
@@ -82,7 +83,9 @@ output(std::ostream &out) const {
     if (_eye_relative) {
       out << " eye";
     }
-    if (_offset != 0.0f) {
+    if (_fixed_depth) {
+      out << " depth " << -_offset;
+    } else if (_offset != 0.0f) {
       out << " offset " << _offset;
     }
     if (!_look_at.is_empty()) {
@@ -201,6 +204,9 @@ compare_to_impl(const RenderEffect *other) const {
   if (_eye_relative != ta->_eye_relative) {
     return (int)_eye_relative - (int)ta->_eye_relative;
   }
+  if (_fixed_depth != ta->_fixed_depth) {
+    return (int)_fixed_depth - (int)ta->_fixed_depth;
+  }
   if (_offset != ta->_offset) {
     return _offset < ta->_offset ? -1 : 1;
   }
@@ -274,11 +280,17 @@ compute_billboard(CPT(TransformState) &node_transform,
 
   // Also slide the billboard geometry towards the camera according to the
   // offset factor.
-  if (_offset != 0.0f) {
+  if (_offset != 0.0f || _fixed_depth) {
     LVector3 translate(rel_mat(3, 0), rel_mat(3, 1), rel_mat(3, 2));
+    LPoint3 pos;
+    if (_fixed_depth) {
+      pos = translate / rel_mat(3, 3);
+    } else {
+      pos.fill(0.0f);
+    }
     translate.normalize();
     translate *= _offset;
-    rotate.set_row(3, translate);
+    rotate.set_row(3, pos + translate);
   }
 
   node_transform = translate->compose(TransformState::make_mat(rotate))->compose(node_transform);
@@ -307,7 +319,25 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   dg.add_stdfloat(_offset);
   _look_at_point.write_datagram(dg);
 
-  // *** We don't write out the _look_at NodePath right now.  Maybe we should.
+  if (manager->get_file_minor_ver() >= 43) {
+    _look_at.write_datagram(manager, dg);
+    dg.add_bool(_fixed_depth);
+  }
+}
+
+/**
+ * Receives an array of pointers, one for each time manager->read_pointer()
+ * was called in fillin(). Returns the number of pointers processed.
+ */
+int BillboardEffect::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = RenderEffect::complete_pointers(p_list, manager);
+
+  if (manager->get_file_minor_ver() >= 43) {
+    pi += _look_at.complete_pointers(p_list + pi, manager);
+  }
+
+  return pi;
 }
 
 /**
@@ -341,4 +371,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _axial_rotate = scan.get_bool();
   _offset = scan.get_stdfloat();
   _look_at_point.read_datagram(scan);
+
+  if (manager->get_file_minor_ver() >= 43) {
+    _look_at.fillin(scan, manager);
+    _fixed_depth = scan.get_bool();
+  }
 }

+ 7 - 2
panda/src/pgraph/billboardEffect.h

@@ -34,7 +34,8 @@ PUBLISHED:
                                 bool axial_rotate,
                                 PN_stdfloat offset,
                                 const NodePath &look_at,
-                                const LPoint3 &look_at_point);
+                                const LPoint3 &look_at_point,
+                                bool fixed_depth = false);
   INLINE static CPT(RenderEffect) make_axis();
   INLINE static CPT(RenderEffect) make_point_eye();
   INLINE static CPT(RenderEffect) make_point_world();
@@ -43,6 +44,7 @@ PUBLISHED:
   INLINE const LVector3 &get_up_vector() const;
   INLINE bool get_eye_relative() const;
   INLINE bool get_axial_rotate() const;
+  INLINE bool get_fixed_depth() const;
   INLINE PN_stdfloat get_offset() const;
   INLINE const NodePath &get_look_at() const;
   INLINE const LPoint3 &get_look_at_point() const;
@@ -72,9 +74,10 @@ private:
 
 private:
   bool _off;
-  LVector3 _up_vector;
   bool _eye_relative;
   bool _axial_rotate;
+  bool _fixed_depth;
+  LVector3 _up_vector;
   PN_stdfloat _offset;
   NodePath _look_at;
   LPoint3 _look_at_point;
@@ -82,6 +85,8 @@ private:
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist,
+                                BamReader *manager);
 
 protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);

+ 23 - 2
panda/src/pgraph/compassEffect.cxx

@@ -284,8 +284,25 @@ void CompassEffect::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderEffect::write_datagram(manager, dg);
   dg.add_uint16(_properties);
-  // *** We don't write out the _reference NodePath right now.  Maybe we
-  // should.
+
+  if (manager->get_file_minor_ver() >= 43) {
+    _reference.write_datagram(manager, dg);
+  }
+}
+
+/**
+ * Receives an array of pointers, one for each time manager->read_pointer()
+ * was called in fillin(). Returns the number of pointers processed.
+ */
+int CompassEffect::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = RenderEffect::complete_pointers(p_list, manager);
+
+  if (manager->get_file_minor_ver() >= 43) {
+    pi += _reference.complete_pointers(p_list + pi, manager);
+  }
+
+  return pi;
 }
 
 /**
@@ -313,4 +330,8 @@ void CompassEffect::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderEffect::fillin(scan, manager);
   _properties = scan.get_uint16();
+
+  if (manager->get_file_minor_ver() >= 43) {
+    _reference.fillin(scan, manager);
+  }
 }

+ 2 - 0
panda/src/pgraph/compassEffect.h

@@ -90,6 +90,8 @@ private:
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist,
+                                BamReader *manager);
 
 protected:
   static TypedWritable *make_from_bam(const FactoryParams &params);

+ 1 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -492,6 +492,7 @@ init_libpgraph() {
   ModelNode::register_with_read_factory();
   ModelRoot::register_with_read_factory();
   PandaNode::register_with_read_factory();
+  ParamNodePath::register_with_read_factory();
   PlaneNode::register_with_read_factory();
   PolylightNode::register_with_read_factory();
   PortalNode::register_with_read_factory();

+ 2 - 2
panda/src/pgraph/nodePath.I

@@ -1752,8 +1752,8 @@ set_billboard_axis(PN_stdfloat offset) {
  * the camera.
  */
 INLINE void NodePath::
-set_billboard_point_eye(PN_stdfloat offset) {
-  set_billboard_point_eye(NodePath(), offset);
+set_billboard_point_eye(PN_stdfloat offset, bool fixed_depth) {
+  set_billboard_point_eye(NodePath(), offset, fixed_depth);
 }
 
 /**

+ 70 - 3
panda/src/pgraph/nodePath.cxx

@@ -4163,6 +4163,20 @@ get_material() const {
   return nullptr;
 }
 
+/**
+ * Recursively searches the scene graph for references to the given material,
+ * and replaces them with the new material.
+ */
+void NodePath::
+replace_material(Material *mat, Material *new_mat) {
+  nassertv_always(!is_empty());
+  nassertv(mat != nullptr);
+  nassertv(new_mat != nullptr);
+
+  CPT(RenderAttrib) new_attrib = MaterialAttrib::make(new_mat);
+  r_replace_material(node(), mat, (const MaterialAttrib *)new_attrib.p());
+}
+
 /**
  * Sets the geometry at this level and below to render using the indicated
  * fog.
@@ -4744,11 +4758,11 @@ set_billboard_axis(const NodePath &camera, PN_stdfloat offset) {
  * the camera, towards a specified "camera" instead of to the viewing camera.
  */
 void NodePath::
-set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset) {
+set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset, bool fixed_depth) {
   nassertv_always(!is_empty());
   CPT(RenderEffect) billboard = BillboardEffect::make
     (LVector3::up(), true, false,
-     offset, camera, LPoint3(0.0f, 0.0f, 0.0f));
+     offset, camera, LPoint3(0.0f, 0.0f, 0.0f), fixed_depth);
   node()->set_effect(billboard);
 }
 
@@ -5677,7 +5691,9 @@ encode_to_bam_stream(vector_uchar &data, BamWriter *writer) const {
 
   // Tell the BamWriter which node is the root node, for making NodePaths
   // relative to when writing them out to the file.
-  writer->set_root_node(node());
+  if (!is_empty()) {
+    writer->set_root_node(node());
+  }
 
   // Write an initial Datagram to represent the error type and number of
   // nodes.
@@ -6632,12 +6648,63 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
   }
 }
 
+/**
+ *
+ */
+void NodePath::
+r_replace_material(PandaNode *node, Material *mat,
+                   const MaterialAttrib *new_attrib) {
+  // Consider the state of the node itself.
+  {
+    CPT(RenderState) node_state = node->get_state();
+    const MaterialAttrib *ma;
+    if (node_state->get_attrib(ma)) {
+      if (mat == ma->get_material()) {
+        node->set_state(node_state->set_attrib(new_attrib));
+      }
+    }
+  }
+
+  // If this is a GeomNode, consider the state of any of its Geoms.
+  if (node->is_geom_node()) {
+    GeomNode *gnode;
+    DCAST_INTO_V(gnode, node);
+
+    int num_geoms = gnode->get_num_geoms();
+    for (int i = 0; i < num_geoms; i++) {
+      CPT(RenderState) geom_state = gnode->get_geom_state(i);
+
+      // Look for a MaterialAttrib on the state.
+      const MaterialAttrib *ma;
+      if (geom_state->get_attrib(ma)) {
+        if (mat == ma->get_material()) {
+          // Replace it
+          gnode->set_geom_state(i, geom_state->set_attrib(new_attrib));
+        }
+      }
+    }
+  }
+
+  // Now consider children.
+  PandaNode::Children cr = node->get_children();
+  size_t num_children = cr.get_num_children();
+  for (size_t i = 0; i < num_children; ++i) {
+    PandaNode *child = cr.get_child(i);
+    r_replace_material(child, mat, new_attrib);
+  }
+}
+
 /**
  * Writes the contents of this object to the datagram for shipping out to a
  * Bam file.
  */
 void NodePath::
 write_datagram(BamWriter *manager, Datagram &dg) const {
+  if (is_empty()) {
+    manager->write_pointer(dg, nullptr);
+    return;
+  }
+
   PandaNode *root = DCAST(PandaNode, manager->get_root_node());
 
   // We have no root node to measure from.

+ 5 - 2
panda/src/pgraph/nodePath.h

@@ -771,6 +771,7 @@ PUBLISHED:
   void clear_material();
   bool has_material() const;
   PT(Material) get_material() const;
+  void replace_material(Material *mat, Material *new_mat);
 
   void set_fog(Fog *fog, int priority = 0);
   void set_fog_off(int priority = 0);
@@ -815,10 +816,10 @@ PUBLISHED:
   void do_billboard_point_eye(const NodePath &camera, PN_stdfloat offset);
   void do_billboard_point_world(const NodePath &camera, PN_stdfloat offset);
   INLINE void set_billboard_axis(PN_stdfloat offset = 0.0);
-  INLINE void set_billboard_point_eye(PN_stdfloat offset = 0.0);
+  INLINE void set_billboard_point_eye(PN_stdfloat offset = 0.0, bool fixed_depth = false);
   INLINE void set_billboard_point_world(PN_stdfloat offset = 0.0);
   void set_billboard_axis(const NodePath &camera, PN_stdfloat offset);
-  void set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset);
+  void set_billboard_point_eye(const NodePath &camera, PN_stdfloat offset, bool fixed_depth = false);
   void set_billboard_point_world(const NodePath &camera, PN_stdfloat offset);
   void clear_billboard();
   bool has_billboard() const;
@@ -1016,6 +1017,8 @@ private:
                           const GlobPattern &glob) const;
   void r_find_all_materials(PandaNode *node, const RenderState *state,
                            Materials &materials) const;
+  static void r_replace_material(PandaNode *node, Material *mat,
+                                 const MaterialAttrib *new_attrib);
 
   PT(NodePathComponent) _head;
   int _backup_key;

+ 2 - 1
panda/src/putil/bam.h

@@ -32,7 +32,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 6 on 2006-02-11 to factor out PandaNode::CData.
 
 static const unsigned short _bam_first_minor_ver = 14;
-static const unsigned short _bam_minor_ver = 42;
+static const unsigned short _bam_minor_ver = 43;
 // Bumped to minor version 14 on 2007-12-19 to change default ColorAttrib.
 // Bumped to minor version 15 on 2008-04-09 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 16 on 2008-05-13 to add Texture::_quality_level.
@@ -62,5 +62,6 @@ static const unsigned short _bam_minor_ver = 42;
 // Bumped to minor version 40 on 2016-01-11 to make NodePaths writable.
 // Bumped to minor version 41 on 2016-03-02 to change LensNode, Lens, and Camera.
 // Bumped to minor version 42 on 2016-04-08 to expand ColorBlendAttrib.
+// Bumped to minor version 43 on 2018-12-06 to expand BillboardEffect and CompassEffect.
 
 #endif

+ 20 - 0
panda/src/x11display/x11GraphicsWindow.cxx

@@ -508,6 +508,26 @@ process_events() {
     changed_properties = true;
   }
 
+  if (properties.has_foreground() && _properties.get_mouse_mode() == WindowProperties::M_confined) {
+      // Focus has changed, let's let go of the pointer if we've grabbed or re-grab it if needed
+      if (properties.get_foreground()) {
+        // Window is going to the foreground, re-grab the pointer
+        X11_Cursor cursor = None;
+        if (_properties.get_cursor_hidden()) {
+            x11GraphicsPipe *x11_pipe;
+            DCAST_INTO_V(x11_pipe, _pipe);
+            cursor = x11_pipe->get_hidden_cursor();
+        }
+
+        XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, GrabModeAsync,
+                    _xwindow, cursor, CurrentTime);
+      }
+      else {
+        // window is leaving the foreground, ungrab the pointer
+        XUngrabPointer(_display, CurrentTime);
+      }
+  }
+
   if (changed_properties) {
     system_changed_properties(properties);
   }

+ 85 - 0
tests/dtoolutil/test_globpattern.py

@@ -0,0 +1,85 @@
+from panda3d.core import GlobPattern
+
+
+def test_globpattern_matches_file():
+    patt = GlobPattern('/a/b/c')
+    assert patt.matches_file('/a/b/c')
+    assert patt.matches_file('///a////b//c')
+    assert patt.matches_file('/a/b/././c')
+    assert not patt.matches_file('')
+    assert not patt.matches_file('/')
+    assert not patt.matches_file('/a/b/d')
+    assert not patt.matches_file('/A/b/c')
+    assert not patt.matches_file('/a/b/c/')
+    assert not patt.matches_file('/a/b/c/.')
+    assert not patt.matches_file('a/b/c')
+    assert not patt.matches_file('./a/b/c')
+
+    # Test regular pattern
+    patt = GlobPattern('*a')
+    assert patt.matches_file('a')
+    assert patt.matches_file('aa')
+    assert patt.matches_file('xa')
+    assert not patt.matches_file('A')
+    assert not patt.matches_file('ax')
+    assert not patt.matches_file('xax')
+
+    # Test path ending in directory
+    for patt in GlobPattern('/a/b/c/'), \
+                GlobPattern('/a/b/c/.'), \
+                GlobPattern('/a/b//c//'), \
+                GlobPattern('/a/b/./c/./'):
+        assert patt.matches_file('/a/b/c/')
+        assert patt.matches_file('///a////b//c//')
+        assert patt.matches_file('/a/b/././c/')
+        assert patt.matches_file('/a/b/c/.')
+        assert not patt.matches_file('/a/b/c')
+        assert not patt.matches_file('/a/b/c/./d')
+        assert not patt.matches_file('a/b/c/')
+        assert not patt.matches_file('./a/b/c/')
+
+    # Test globstar in middle
+    for patt in GlobPattern('/a/**/c'), GlobPattern('/a/**/**/c'):
+        assert patt.matches_file('/a/c')
+        assert patt.matches_file('/a/b/c')
+        assert patt.matches_file('/a/b/d/c')
+        assert not patt.matches_file('/a/b/c/d')
+        assert not patt.matches_file('/d/b/c')
+        assert not patt.matches_file('/a/b/d')
+
+    # Test globstar in beginning
+    for patt in GlobPattern('/**/b/c'), GlobPattern('/**/**/**/b/c'):
+        assert patt.matches_file('/a/b/c')
+        assert patt.matches_file('/a/d/b/c')
+        assert patt.matches_file('/a/b/c')
+        assert patt.matches_file('/a/b/c/./b//c')
+        assert not patt.matches_file('/a/b/c/d')
+        assert not patt.matches_file('/a/c')
+        assert not patt.matches_file('/a/b/d')
+
+    # Test globstar at end
+    for patt in GlobPattern('/a/b/**'), \
+                GlobPattern('/a/b/**/**'), \
+                GlobPattern('/a/b//**//**/**'):
+        assert patt.matches_file('/a/b/')
+        assert patt.matches_file('/a/b/.')
+        assert patt.matches_file('/a/b//')
+        assert patt.matches_file('/a/b/c')
+        assert patt.matches_file('/a/b/c/d/e/f/g/h')
+        assert patt.matches_file('/a/b/d/c')
+        assert not patt.matches_file('/a/')
+        assert not patt.matches_file('/a/c/b')
+
+    # Test multiple globstars at multiple locations
+    patt = GlobPattern('/a/**/b/**/c')
+    assert patt.matches_file('/a/b/c')
+    assert patt.matches_file('/a/./b/./c')
+    assert patt.matches_file('/a//b//c')
+    assert patt.matches_file('/a/x/y/b/c')
+    assert patt.matches_file('/a/b/x/y/c')
+    assert patt.matches_file('/a/b/c/a/b/c')
+    assert patt.matches_file('/a/x/y/b/x/y/c')
+    assert not patt.matches_file('/a/b/x')
+    assert not patt.matches_file('/a/b/c/x')
+    assert not patt.matches_file('/a/b/c/')
+    assert not patt.matches_file('/a/b/c/.')

+ 30 - 4
tests/pgraph/test_nodepath.py

@@ -2,13 +2,39 @@ import pytest, sys
 
 def test_nodepath_empty():
     """Tests NodePath behavior for empty NodePaths."""
+    from panda3d.core import NodePath, ParamNodePath
+    import pickle
+
+    empty = NodePath()
+    assert empty.is_empty()
+    assert not empty
+
+    # Try pickling, which uses __reduce__
+    dumped = pickle.dumps(empty)
+    empty2 = pickle.loads(dumped)
+    assert empty2.is_empty()
+    assert not empty2
+    assert empty == empty2
+
+    # Test write_datagram/fillin, which are invoked when the NodePath is being
+    # serialized indirectly, such as via ParamNodePath
+    dumped = pickle.dumps(ParamNodePath(empty))
+    empty2 = pickle.loads(dumped).get_value()
+    assert empty2.is_empty()
+    assert not empty2
+    assert empty == empty2
+
+def test_nodepath_single():
+    """Tests NodePath behavior for single-node NodePaths."""
     from panda3d.core import NodePath
 
-    empty = NodePath('np')
+    np = NodePath('np')
+    assert not np.is_empty()
+    assert np
 
-    assert empty.get_pos() == (0, 0, 0)
-    assert empty.get_hpr() == (0, 0, 0)
-    assert empty.get_scale() == (1, 1, 1)
+    assert np.get_pos() == (0, 0, 0)
+    assert np.get_hpr() == (0, 0, 0)
+    assert np.get_scale() == (1, 1, 1)
 
 def test_nodepath_parent():
     """Tests NodePath.reparentTo()."""