Browse Source

Merge branch 'release/1.10.x'

rdb 6 years ago
parent
commit
b78b7be326

+ 6 - 3
README.md

@@ -185,16 +185,19 @@ from the Play Store.  Many of the dependencies can be installed by running the
 following command in the Termux shell:
 following command in the Termux shell:
 
 
 ```bash
 ```bash
-pkg install python-dev termux-tools ndk-stl ndk-sysroot clang libvorbis-dev libopus-dev opusfile-dev openal-soft-dev freetype-dev harfbuzz-dev libpng-dev ecj4.6 dx patchelf aapt apksigner libcrypt-dev
+pkg install python ndk-sysroot clang bison freetype harfbuzz libpng eigen openal-soft opusfile libvorbis assimp libopus ecj dx patchelf aapt apksigner libcrypt openssl pkg-config
 ```
 ```
 
 
-Then, you can build and install the .apk right away using these commands:
+Then, you can build the .apk using this command:
 
 
 ```bash
 ```bash
 python makepanda/makepanda.py --everything --target android-21 --no-tiff --installer
 python makepanda/makepanda.py --everything --target android-21 --no-tiff --installer
-xdg-open panda3d.apk
 ```
 ```
 
 
+You can install the generated panda3d.apk by browsing to the panda3d folder
+using a file manager.  You may need to copy it to `/sdcard` to be able to
+access it from other apps.
+
 To launch a Python program from Termux, you can use the `run_python.sh` script
 To launch a Python program from Termux, you can use the `run_python.sh` script
 inside the `panda/src/android` directory.  It will launch Python in a separate
 inside the `panda/src/android` directory.  It will launch Python in a separate
 activity, load it with the Python script you passed as argument, and use a
 activity, load it with the Python script you passed as argument, and use a

+ 4 - 0
direct/src/actor/Actor.py

@@ -5,6 +5,7 @@ __all__ = ['Actor']
 from panda3d.core import *
 from panda3d.core import *
 from panda3d.core import Loader as PandaLoader
 from panda3d.core import Loader as PandaLoader
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
+from direct.showbase.Loader import Loader
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal
 
 
 
 
@@ -1886,6 +1887,9 @@ class Actor(DirectObject, NodePath):
                 else:
                 else:
                     loaderOptions.setFlags(loaderOptions.getFlags() | LoaderOptions.LFReportErrors)
                     loaderOptions.setFlags(loaderOptions.getFlags() | LoaderOptions.LFReportErrors)
 
 
+            # Ensure that custom Python loader hooks are initialized.
+            Loader._loadPythonFileTypes()
+
             # Pass loaderOptions to specify that we want to
             # Pass loaderOptions to specify that we want to
             # get the skeleton model.  This only matters to model
             # get the skeleton model.  This only matters to model
             # files (like .mb) for which we can choose to extract
             # files (like .mb) for which we can choose to extract

+ 3 - 3
direct/src/dcparser/dcPackerInterface.I

@@ -253,8 +253,9 @@ do_unpack_int64(const char *buffer) {
                     ((uint64_t)(unsigned char)buffer[4] << 32) |
                     ((uint64_t)(unsigned char)buffer[4] << 32) |
                     ((uint64_t)(unsigned char)buffer[5] << 40) |
                     ((uint64_t)(unsigned char)buffer[5] << 40) |
                     ((uint64_t)(unsigned char)buffer[6] << 48) |
                     ((uint64_t)(unsigned char)buffer[6] << 48) |
-                    ((int64_t)(signed char)buffer[7] << 54));
+                    ((int64_t)(signed char)buffer[7] << 56));
 }
 }
+
 /**
 /**
  *
  *
  */
  */
@@ -295,10 +296,9 @@ do_unpack_uint64(const char *buffer) {
           ((uint64_t)(unsigned char)buffer[4] << 32) |
           ((uint64_t)(unsigned char)buffer[4] << 32) |
           ((uint64_t)(unsigned char)buffer[5] << 40) |
           ((uint64_t)(unsigned char)buffer[5] << 40) |
           ((uint64_t)(unsigned char)buffer[6] << 48) |
           ((uint64_t)(unsigned char)buffer[6] << 48) |
-          ((int64_t)(signed char)buffer[7] << 54));
+          ((uint64_t)(unsigned char)buffer[7] << 56));
 }
 }
 
 
-
 /**
 /**
  *
  *
  */
  */

+ 0 - 1
direct/src/dcparser/dcPackerInterface.h

@@ -16,7 +16,6 @@
 
 
 #include "dcbase.h"
 #include "dcbase.h"
 #include "dcSubatomicType.h"
 #include "dcSubatomicType.h"
-#include "vector_uchar.h"
 
 
 class DCFile;
 class DCFile;
 class DCField;
 class DCField;

+ 0 - 1
direct/src/dcparser/dcParserDefs.h

@@ -16,7 +16,6 @@
 
 
 #include "dcbase.h"
 #include "dcbase.h"
 #include "dcSubatomicType.h"
 #include "dcSubatomicType.h"
-#include "vector_uchar.h"
 
 
 class DCFile;
 class DCFile;
 class DCClass;
 class DCClass;

+ 4 - 0
direct/src/dcparser/dcbase.h

@@ -32,6 +32,7 @@
 #include "pvector.h"
 #include "pvector.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "pset.h"
 #include "pset.h"
+#include "vector_uchar.h"
 
 
 #else  // WITHIN_PANDA
 #else  // WITHIN_PANDA
 
 
@@ -81,6 +82,7 @@
 #define nassertr_always(condition, return_value) assert(condition)
 #define nassertr_always(condition, return_value) assert(condition)
 #define nassertv(condition) assert(condition)
 #define nassertv(condition) assert(condition)
 #define nassertv_always(condition) assert(condition)
 #define nassertv_always(condition) assert(condition)
+#define nassert_raise(message) {std::cerr << message << std::endl; abort();}
 
 
 // Panda defines a special Filename class.  We'll use an ordinary string
 // Panda defines a special Filename class.  We'll use an ordinary string
 // instead.
 // instead.
@@ -97,8 +99,10 @@ typedef std::string Filename;
 #define pvector std::vector
 #define pvector std::vector
 #define pmap std::map
 #define pmap std::map
 #define pset std::set
 #define pset std::set
+#define vector_uchar std::vector<unsigned char>
 
 
 #include <stdint.h>
 #include <stdint.h>
+#include <string.h>
 
 
 typedef std::ifstream pifstream;
 typedef std::ifstream pifstream;
 typedef std::ofstream pofstream;
 typedef std::ofstream pofstream;

+ 0 - 1
direct/src/dcparser/hashGenerator.h

@@ -16,7 +16,6 @@
 
 
 #include "dcbase.h"
 #include "dcbase.h"
 #include "primeNumberGenerator.h"
 #include "primeNumberGenerator.h"
-#include "vector_uchar.h"
 
 
 /**
 /**
  * This class generates an arbitrary hash number from a sequence of ints.
  * This class generates an arbitrary hash number from a sequence of ints.

+ 13 - 3
direct/src/showbase/Loader.py

@@ -22,6 +22,8 @@ class Loader(DirectObject):
     notify = directNotify.newCategory("Loader")
     notify = directNotify.newCategory("Loader")
     loaderIndex = 0
     loaderIndex = 0
 
 
+    _loadedPythonFileTypes = False
+
     class Callback:
     class Callback:
         """Returned by loadModel when used asynchronously.  This class is
         """Returned by loadModel when used asynchronously.  This class is
         modelled after Future, and can be awaited."""
         modelled after Future, and can be awaited."""
@@ -149,8 +151,7 @@ class Loader(DirectObject):
         Loader.loaderIndex += 1
         Loader.loaderIndex += 1
         self.accept(self.hook, self.__gotAsyncObject)
         self.accept(self.hook, self.__gotAsyncObject)
 
 
-        if ConfigVariableBool('loader-support-entry-points', True):
-            self._loadPythonFileTypes()
+        self._loadPythonFileTypes()
 
 
     def destroy(self):
     def destroy(self):
         self.ignore(self.hook)
         self.ignore(self.hook)
@@ -158,7 +159,14 @@ class Loader(DirectObject):
         del self.base
         del self.base
         del self.loader
         del self.loader
 
 
-    def _loadPythonFileTypes(self):
+    @classmethod
+    def _loadPythonFileTypes(cls):
+        if cls._loadedPythonFileTypes:
+            return
+
+        if not ConfigVariableBool('loader-support-entry-points', True):
+            return
+
         import importlib
         import importlib
         try:
         try:
             pkg_resources = importlib.import_module('pkg_resources')
             pkg_resources = importlib.import_module('pkg_resources')
@@ -171,6 +179,8 @@ class Loader(DirectObject):
             for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'):
             for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'):
                 registry.register_deferred_type(entry_point)
                 registry.register_deferred_type(entry_point)
 
 
+            cls._loadedPythonFileTypes = True
+
     # model loading funcs
     # model loading funcs
     def loadModel(self, modelPath, loaderOptions = None, noCache = None,
     def loadModel(self, modelPath, loaderOptions = None, noCache = None,
                   allowInstance = False, okMissing = None,
                   allowInstance = False, okMissing = None,

+ 5 - 2
direct/src/stdpy/threading.py

@@ -87,7 +87,7 @@ class Thread(ThreadBase):
     object.  The wrapper is designed to emulate Python's own
     object.  The wrapper is designed to emulate Python's own
     threading.Thread object. """
     threading.Thread object. """
 
 
-    def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
+    def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, daemon=None):
         ThreadBase.__init__(self)
         ThreadBase.__init__(self)
 
 
         assert group is None
         assert group is None
@@ -99,7 +99,10 @@ class Thread(ThreadBase):
             name = _newname()
             name = _newname()
 
 
         current = current_thread()
         current = current_thread()
-        self.__dict__['daemon'] = current.daemon
+        if daemon is not None:
+            self.__dict__['daemon'] = daemon
+        else:
+            self.__dict__['daemon'] = current.daemon
         self.__dict__['name'] = name
         self.__dict__['name'] = name
 
 
         def call_run():
         def call_run():

+ 22 - 3
direct/src/stdpy/threading2.py

@@ -14,6 +14,7 @@ module, and so it is therefore layered on top of Panda's thread
 implementation. """
 implementation. """
 
 
 import sys as _sys
 import sys as _sys
+import atexit as _atexit
 
 
 from direct.stdpy import thread as _thread
 from direct.stdpy import thread as _thread
 from direct.stdpy.thread import stack_size, _newname, _local as local
 from direct.stdpy.thread import stack_size, _newname, _local as local
@@ -395,8 +396,12 @@ class Thread(_Verbose):
     # operation on/with a NoneType
     # operation on/with a NoneType
     __exc_info = _sys.exc_info
     __exc_info = _sys.exc_info
 
 
+    # Set to True when the _shutdown handler is registered as atexit function.
+    # Protected by _active_limbo_lock.
+    __registered_atexit = False
+
     def __init__(self, group=None, target=None, name=None,
     def __init__(self, group=None, target=None, name=None,
-                 args=(), kwargs=None, verbose=None):
+                 args=(), kwargs=None, verbose=None, daemon=None):
         assert group is None, "group argument must be None for now"
         assert group is None, "group argument must be None for now"
         _Verbose.__init__(self, verbose)
         _Verbose.__init__(self, verbose)
         if kwargs is None:
         if kwargs is None:
@@ -405,7 +410,10 @@ class Thread(_Verbose):
         self.__name = str(name or _newname())
         self.__name = str(name or _newname())
         self.__args = args
         self.__args = args
         self.__kwargs = kwargs
         self.__kwargs = kwargs
-        self.__daemonic = self._set_daemon()
+        if daemon is not None:
+            self.__daemonic = daemon
+        else:
+            self.__daemonic = self._set_daemon()
         self.__started = False
         self.__started = False
         self.__stopped = False
         self.__stopped = False
         self.__block = Condition(Lock())
         self.__block = Condition(Lock())
@@ -436,6 +444,14 @@ class Thread(_Verbose):
             self._note("%s.start(): starting thread", self)
             self._note("%s.start(): starting thread", self)
         _active_limbo_lock.acquire()
         _active_limbo_lock.acquire()
         _limbo[self] = self
         _limbo[self] = self
+
+        # If we are starting a non-daemon thread, we need to call join() on it
+        # when the interpreter exits.  Python will call _shutdown() on the
+        # built-in threading module automatically, but not on our module.
+        if not self.__daemonic and not Thread.__registered_atexit:
+            _atexit.register(_shutdown)
+            Thread.__registered_atexit = True
+
         _active_limbo_lock.release()
         _active_limbo_lock.release()
         _start_new_thread(self.__bootstrap, ())
         _start_new_thread(self.__bootstrap, ())
         self.__started = True
         self.__started = True
@@ -599,6 +615,9 @@ class Thread(_Verbose):
         assert not self.__started, "cannot set daemon status of active thread"
         assert not self.__started, "cannot set daemon status of active thread"
         self.__daemonic = daemonic
         self.__daemonic = daemonic
 
 
+    name = property(getName, setName)
+    daemon = property(isDaemon, setDaemon)
+
 # The timer class was contributed by Itamar Shtull-Trauring
 # The timer class was contributed by Itamar Shtull-Trauring
 
 
 def Timer(*args, **kwargs):
 def Timer(*args, **kwargs):
@@ -670,7 +689,7 @@ class _MainThread(Thread):
 class _DummyThread(Thread):
 class _DummyThread(Thread):
 
 
     def __init__(self):
     def __init__(self):
-        Thread.__init__(self, name=_newname("Dummy-%d"))
+        Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True)
 
 
         # Thread.__block consumes an OS-level locking primitive, which
         # Thread.__block consumes an OS-level locking primitive, which
         # can never be used by a _DummyThread.  Since a _DummyThread
         # can never be used by a _DummyThread.  Since a _DummyThread

+ 3 - 6
dtool/src/interrogatedb/py_compat.h

@@ -141,16 +141,13 @@ typedef long Py_hash_t;
 
 
 #if PY_VERSION_HEX < 0x03080000 && !defined(_PyObject_CallNoArg)
 #if PY_VERSION_HEX < 0x03080000 && !defined(_PyObject_CallNoArg)
 INLINE PyObject *_PyObject_CallNoArg(PyObject *func) {
 INLINE PyObject *_PyObject_CallNoArg(PyObject *func) {
-  static PyTupleObject empty_tuple = {PyVarObject_HEAD_INIT(nullptr, 0)};
-#ifdef Py_TRACE_REFS
-  _Py_AddToAllObjects((PyObject *)&empty_tuple, 0);
-#endif
-  return PyObject_Call(func, (PyObject *)&empty_tuple, nullptr);
+  static PyObject *empty_tuple = PyTuple_New(0);
+  return PyObject_Call(func, empty_tuple, nullptr);
 }
 }
 #  define _PyObject_CallNoArg _PyObject_CallNoArg
 #  define _PyObject_CallNoArg _PyObject_CallNoArg
 #endif
 #endif
 
 
-#ifndef _PyObject_FastCall
+#if PY_VERSION_HEX < 0x03080000 && !defined(_PyObject_FastCall)
 INLINE PyObject *_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) {
 INLINE PyObject *_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) {
   PyObject *tuple = PyTuple_New(nargs);
   PyObject *tuple = PyTuple_New(nargs);
   for (Py_ssize_t i = 0; i < nargs; ++i) {
   for (Py_ssize_t i = 0; i < nargs; ++i) {

+ 11 - 3
makepanda/makepanda.py

@@ -944,11 +944,12 @@ if (COMPILER=="GCC"):
     for pkg in MAYAVERSIONS:
     for pkg in MAYAVERSIONS:
         if (PkgSkip(pkg)==0 and (pkg in SDK)):
         if (PkgSkip(pkg)==0 and (pkg in SDK)):
             if GetTarget() == 'darwin':
             if GetTarget() == 'darwin':
-                LibName(pkg, "-Wl,-rpath," + SDK[pkg] + "/Maya.app/Contents/MacOS")
+                LibName(pkg, "-Wl,-rpath,/Applications/Autodesk/" + pkg.lower() + "/Maya.app/Contents/MacOS")
             else:
             else:
                 LibName(pkg, "-Wl,-rpath," + SDK[pkg] + "/lib")
                 LibName(pkg, "-Wl,-rpath," + SDK[pkg] + "/lib")
             LibName(pkg, "-lOpenMaya")
             LibName(pkg, "-lOpenMaya")
             LibName(pkg, "-lOpenMayaAnim")
             LibName(pkg, "-lOpenMayaAnim")
+            LibName(pkg, "-lOpenMayaUI")
             LibName(pkg, "-lAnimSlice")
             LibName(pkg, "-lAnimSlice")
             LibName(pkg, "-lDeformSlice")
             LibName(pkg, "-lDeformSlice")
             LibName(pkg, "-lModifiers")
             LibName(pkg, "-lModifiers")
@@ -967,7 +968,8 @@ if (COMPILER=="GCC"):
             LibName(pkg, "-lDependEngine")
             LibName(pkg, "-lDependEngine")
             LibName(pkg, "-lCommandEngine")
             LibName(pkg, "-lCommandEngine")
             LibName(pkg, "-lFoundation")
             LibName(pkg, "-lFoundation")
-            LibName(pkg, "-lIMFbase")
+            if pkg != "MAYA2020":
+                LibName(pkg, "-lIMFbase")
             if GetTarget() != 'darwin':
             if GetTarget() != 'darwin':
                 LibName(pkg, "-lOpenMayalib")
                 LibName(pkg, "-lOpenMayalib")
             else:
             else:
@@ -2612,7 +2614,13 @@ if not PkgSkip("PYTHON"):
     ConditionalWriteFile(GetOutputDir() + '/panda3d/__init__.py', p3d_init)
     ConditionalWriteFile(GetOutputDir() + '/panda3d/__init__.py', p3d_init)
 
 
     # Also add this file, for backward compatibility.
     # Also add this file, for backward compatibility.
-    ConditionalWriteFile(GetOutputDir() + '/panda3d/dtoolconfig.py', """
+    ConditionalWriteFile(GetOutputDir() + '/panda3d/dtoolconfig.py', """\
+'''Alias of :mod:`panda3d.interrogatedb`.
+
+.. deprecated:: 1.10.0
+   This module has been renamed to :mod:`panda3d.interrogatedb`.
+'''
+
 if __debug__:
 if __debug__:
     print("Warning: panda3d.dtoolconfig is deprecated, use panda3d.interrogatedb instead.")
     print("Warning: panda3d.dtoolconfig is deprecated, use panda3d.interrogatedb instead.")
 from .interrogatedb import *
 from .interrogatedb import *

+ 2 - 1
makepanda/makepandacore.py

@@ -106,6 +106,7 @@ MAYAVERSIONINFO = [("MAYA6",   "6.0"),
                    ("MAYA2017","2017"),
                    ("MAYA2017","2017"),
                    ("MAYA2018","2018"),
                    ("MAYA2018","2018"),
                    ("MAYA2019","2019"),
                    ("MAYA2019","2019"),
+                   ("MAYA2020","2020"),
 ]
 ]
 
 
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),
@@ -2803,7 +2804,7 @@ def SetupVisualStudioEnviron():
         elif not win_kit.endswith('\\'):
         elif not win_kit.endswith('\\'):
             win_kit += '\\'
             win_kit += '\\'
 
 
-        for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763:
+        for vnum in 10150, 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362:
             version = "10.0.{0}.0".format(vnum)
             version = "10.0.{0}.0".format(vnum)
             if os.path.isfile(win_kit + "Include\\" + version + "\\ucrt\\assert.h"):
             if os.path.isfile(win_kit + "Include\\" + version + "\\ucrt\\assert.h"):
                 print("Using Universal CRT %s" % (version))
                 print("Using Universal CRT %s" % (version))

+ 5 - 0
makepanda/makewheel.py

@@ -701,10 +701,15 @@ if __debug__:
             # Put the .exe files inside the panda3d-tools directory.
             # Put the .exe files inside the panda3d-tools directory.
             whl.write_file('panda3d_tools/' + file, source_path)
             whl.write_file('panda3d_tools/' + file, source_path)
 
 
+            if basename.endswith('_bin'):
+                # These tools won't be invoked by the user directly.
+                continue
+
             # Tell pip to create a wrapper script.
             # Tell pip to create a wrapper script.
             funcname = basename.replace('-', '_')
             funcname = basename.replace('-', '_')
             entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
             entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
             tools_init += '{0} = lambda: _exec_tool({1!r})\n'.format(funcname, file)
             tools_init += '{0} = lambda: _exec_tool({1!r})\n'.format(funcname, file)
+
     entry_points += '[distutils.commands]\n'
     entry_points += '[distutils.commands]\n'
     entry_points += 'build_apps = direct.dist.commands:build_apps\n'
     entry_points += 'build_apps = direct.dist.commands:build_apps\n'
     entry_points += 'bdist_apps = direct.dist.commands:bdist_apps\n'
     entry_points += 'bdist_apps = direct.dist.commands:bdist_apps\n'

+ 42 - 1
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -45,6 +45,10 @@
 
 
 TypeHandle CocoaGraphicsWindow::_type_handle;
 TypeHandle CocoaGraphicsWindow::_type_handle;
 
 
+#ifndef MAC_OS_X_VERSION_10_15
+#define NSAppKitVersionNumber10_14 1671
+#endif
+
 /**
 /**
  *
  *
  */
  */
@@ -1095,7 +1099,28 @@ set_properties_now(WindowProperties &properties) {
  */
  */
 CGDisplayModeRef CocoaGraphicsWindow::
 CGDisplayModeRef CocoaGraphicsWindow::
 find_display_mode(int width, int height) {
 find_display_mode(int width, int height) {
-  CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL);
+  CFDictionaryRef options = NULL;
+  // On macOS 10.15+ (Catalina), we want to select the display mode with the
+  // samescaling factor as the current view to avoid cropping or scaling issues.
+  // This is a workaround until HiDPI display or scaling factor is properly
+  // handled. CGDisplayCopyAllDisplayModes() does not return upscaled display
+  // mode unless explicitly asked with kCGDisplayShowDuplicateLowResolutionModes
+  // (which is undocumented...).
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+  if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_14) {
+    const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
+    const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
+    options = CFDictionaryCreate(NULL,
+                                 (const void **)dictkeys,
+                                 (const void **)dictvalues,
+                                 1,
+                                 &kCFCopyStringDictionaryKeyCallBacks,
+                                 &kCFTypeDictionaryValueCallBacks);
+  }
+#endif
+  CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, options);
+  CFRelease(options);
+
   size_t num_modes = CFArrayGetCount(modes);
   size_t num_modes = CFArrayGetCount(modes);
   CGDisplayModeRef mode;
   CGDisplayModeRef mode;
 
 
@@ -1104,14 +1129,22 @@ find_display_mode(int width, int height) {
   int refresh_rate;
   int refresh_rate;
   mode = CGDisplayCopyDisplayMode(_display);
   mode = CGDisplayCopyDisplayMode(_display);
 
 
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080
   // First check if the current mode is adequate.
   // First check if the current mode is adequate.
   if (CGDisplayModeGetWidth(mode) == width &&
   if (CGDisplayModeGetWidth(mode) == width &&
       CGDisplayModeGetHeight(mode) == height) {
       CGDisplayModeGetHeight(mode) == height) {
     return mode;
     return mode;
   }
   }
+#endif
 
 
   current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
   current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
   refresh_rate = CGDisplayModeGetRefreshRate(mode);
   refresh_rate = CGDisplayModeGetRefreshRate(mode);
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+  // Calculate the pixel width and height of the fullscreen mode we want using
+  // the currentdisplay mode dimensions and pixel dimensions.
+  size_t expected_pixel_width = (size_t(width) * CGDisplayModeGetPixelWidth(mode)) / CGDisplayModeGetWidth(mode);
+  size_t expected_pixel_height = (size_t(height) * CGDisplayModeGetPixelHeight(mode)) / CGDisplayModeGetHeight(mode);
+#endif
   CGDisplayModeRelease(mode);
   CGDisplayModeRelease(mode);
 
 
   for (size_t i = 0; i < num_modes; ++i) {
   for (size_t i = 0; i < num_modes; ++i) {
@@ -1119,9 +1152,17 @@ find_display_mode(int width, int height) {
 
 
     CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
     CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
 
 
+    // As explained above, we want to select the fullscreen display mode using
+    // the same scaling factor, but only for MacOS 10.15+ To do this we check
+    // the mode width and heightbut also actual pixel widh and height.
     if (CGDisplayModeGetWidth(mode) == width &&
     if (CGDisplayModeGetWidth(mode) == width &&
         CGDisplayModeGetHeight(mode) == height &&
         CGDisplayModeGetHeight(mode) == height &&
         CGDisplayModeGetRefreshRate(mode) == refresh_rate &&
         CGDisplayModeGetRefreshRate(mode) == refresh_rate &&
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+        (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_14 ||
+        (CGDisplayModeGetPixelWidth(mode) == expected_pixel_width &&
+         CGDisplayModeGetPixelHeight(mode) == expected_pixel_height)) &&
+#endif
         CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
         CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
 
 
       CFRetain(mode);
       CFRetain(mode);

+ 39 - 6
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -496,6 +496,7 @@ prepare_vertex_buffer(GeomVertexArrayData *data) {
     }
     }
     #endif
     #endif
 
 
+    dvbc->update_data_size_bytes(num_bytes);
     return dvbc;
     return dvbc;
   } else {
   } else {
     dxgsg9_cat.error()
     dxgsg9_cat.error()
@@ -533,14 +534,42 @@ apply_vertex_buffer(VertexBufferContext *vbc,
         return false;
         return false;
       }
       }
 
 
-      PStatTimer timer(_load_vertex_buffer_pcollector, reader->get_current_thread());
 
 
-      #if 0
       if (dvbc->changed_size(reader)) {
       if (dvbc->changed_size(reader)) {
-        // We have to destroy the old vertex buffer and create a new one.
-        dvbc->create_vbuffer(*_screen, reader);
+        // Destroy and recreate the buffer.
+        if (dvbc->_vbuffer != nullptr) {
+          dvbc->_vbuffer->Release();
+          dvbc->_vbuffer = nullptr;
+        }
+
+        DWORD usage;
+        D3DPOOL pool;
+        if (_screen->_managed_vertex_buffers) {
+          pool = D3DPOOL_MANAGED;
+          usage = D3DUSAGE_WRITEONLY;
+        } else {
+          pool = D3DPOOL_DEFAULT;
+          usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
+        }
+
+        PStatTimer timer(_create_vertex_buffer_pcollector, Thread::get_current_thread());
+
+        HRESULT hr;
+        int attempts = 0;
+        do {
+          hr = _screen->_d3d_device->CreateVertexBuffer(num_bytes, usage, dvbc->_fvf, pool, &dvbc->_vbuffer, nullptr);
+          attempts++;
+        } while (check_dx_allocation(hr, num_bytes, attempts));
+
+        if (FAILED(hr)) {
+          dvbc->_vbuffer = nullptr;
+          dxgsg9_cat.error()
+            << "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
+          return false;
+        }
       }
       }
-      #endif
+
+      PStatTimer timer(_load_vertex_buffer_pcollector, reader->get_current_thread());
 
 
       HRESULT hr;
       HRESULT hr;
       BYTE *local_pointer;
       BYTE *local_pointer;
@@ -5240,6 +5269,7 @@ calc_fb_properties(DWORD cformat, DWORD dformat,
 #define GAMMA_1 (255.0 * 256.0)
 #define GAMMA_1 (255.0 * 256.0)
 
 
 static bool _gamma_table_initialized = false;
 static bool _gamma_table_initialized = false;
+static bool _gamma_changed = false;
 static unsigned short _original_gamma_table [256 * 3];
 static unsigned short _original_gamma_table [256 * 3];
 
 
 void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
 void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
@@ -5337,6 +5367,7 @@ static_set_gamma(bool restore, PN_stdfloat gamma) {
 
 
     if (SetDeviceGammaRamp (hdc, ramp)) {
     if (SetDeviceGammaRamp (hdc, ramp)) {
       set = true;
       set = true;
+      _gamma_changed = !restore;
     }
     }
 
 
     ReleaseDC (nullptr, hdc);
     ReleaseDC (nullptr, hdc);
@@ -5374,7 +5405,9 @@ restore_gamma() {
 void DXGraphicsStateGuardian9::
 void DXGraphicsStateGuardian9::
 atexit_function(void) {
 atexit_function(void) {
   set_cg_device(nullptr);
   set_cg_device(nullptr);
-  static_set_gamma(true, 1.0f);
+  if (_gamma_changed) {
+    static_set_gamma(true, 1.0f);
+  }
 }
 }
 
 
 /**
 /**

+ 22 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2523,6 +2523,20 @@ reset() {
   }
   }
 #endif
 #endif
 
 
+#if defined(OPENGLES) && !defined(OPENGLES_1)
+  if (is_at_least_gles_version(3, 0)) {
+    _glReadBuffer = (PFNGLREADBUFFERPROC)
+      get_extension_func("glReadBuffer");
+
+  } else if (has_extension("GL_NV_read_buffer")) {
+    _glReadBuffer = (PFNGLREADBUFFERPROC)
+      get_extension_func("glReadBufferNV");
+
+  } else {
+    _glReadBuffer = nullptr;
+  }
+#endif
+
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   _max_color_targets = 1;
   _max_color_targets = 1;
   if (_glDrawBuffers != nullptr) {
   if (_glDrawBuffers != nullptr) {
@@ -9060,7 +9074,7 @@ set_draw_buffer(int rbtype) {
  */
  */
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
 set_read_buffer(int rbtype) {
 set_read_buffer(int rbtype) {
-#ifndef OPENGLES  // Draw buffers not supported by OpenGL ES. (TODO!)
+#ifndef OPENGLES_1  // Draw buffers not supported by OpenGL ES 1.
   if (rbtype & (RenderBuffer::T_depth | RenderBuffer::T_stencil)) {
   if (rbtype & (RenderBuffer::T_depth | RenderBuffer::T_stencil)) {
     // Special case: don't have to call ReadBuffer for these.
     // Special case: don't have to call ReadBuffer for these.
     return;
     return;
@@ -9093,10 +9107,14 @@ set_read_buffer(int rbtype) {
       }
       }
       ++index;
       ++index;
     }
     }
+#ifdef OPENGLES
+    _glReadBuffer(buffer);
+#else
     glReadBuffer(buffer);
     glReadBuffer(buffer);
+#endif
 
 
   } else {
   } else {
-
+#ifndef OPENGLES
     switch (rbtype & RenderBuffer::T_color) {
     switch (rbtype & RenderBuffer::T_color) {
     case RenderBuffer::T_front:
     case RenderBuffer::T_front:
       glReadBuffer(GL_FRONT);
       glReadBuffer(GL_FRONT);
@@ -9133,10 +9151,11 @@ set_read_buffer(int rbtype) {
     default:
     default:
       break;
       break;
     }
     }
+#endif  // OPENGLES
   }
   }
 
 
   report_my_gl_errors();
   report_my_gl_errors();
-#endif  // OPENGLES
+#endif  // OPENGLES_1
 }
 }
 
 
 /**
 /**

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

@@ -92,6 +92,7 @@ typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
 typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
 typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
 typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
 typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
 typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
 typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLREADBUFFERPROC) (GLenum src);
 typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
 typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
@@ -939,6 +940,10 @@ public:
   PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
   PFNGLBLITFRAMEBUFFEREXTPROC _glBlitFramebuffer;
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
   PFNGLDRAWBUFFERSPROC _glDrawBuffers;
 
 
+#if defined(OPENGLES) && !defined(OPENGLES_1)
+  PFNGLREADBUFFERPROC _glReadBuffer;
+#endif
+
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
   PFNGLCLEARBUFFERFVPROC _glClearBufferfv;
   PFNGLCLEARBUFFERFVPROC _glClearBufferfv;
   PFNGLCLEARBUFFERIVPROC _glClearBufferiv;
   PFNGLCLEARBUFFERIVPROC _glClearBufferiv;

+ 4 - 4
panda/src/x11display/x11GraphicsPipe.cxx

@@ -371,13 +371,13 @@ find_fullscreen_crtc(const LPoint2i &point,
     for (int i = 0; i < res->ncrtc; ++i) {
     for (int i = 0; i < res->ncrtc; ++i) {
       RRCrtc crtc = res->crtcs[i];
       RRCrtc crtc = res->crtcs[i];
       if (auto info = get_crtc_info(res.get(), crtc)) {
       if (auto info = get_crtc_info(res.get(), crtc)) {
-        if (point[0] >= info->x && point[0] < info->x + info->width &&
-            point[1] >= info->y && point[1] < info->y + info->height) {
+        if (point[0] >= info->x && point[0] < info->x + (int)info->width &&
+            point[1] >= info->y && point[1] < info->y + (int)info->height) {
 
 
           x = info->x;
           x = info->x;
           y = info->y;
           y = info->y;
-          width = info->width;
-          height = info->height;
+          width = (int)info->width;
+          height = (int)info->height;
           return crtc;
           return crtc;
         }
         }
       }
       }

+ 15 - 18
pandatool/src/mayaprogs/mayapath.cxx

@@ -107,6 +107,7 @@ struct MayaVerInfo maya_versions[] = {
   { "MAYA2017", "2017"},
   { "MAYA2017", "2017"},
   { "MAYA2018", "2018"},
   { "MAYA2018", "2018"},
   { "MAYA2019", "2019"},
   { "MAYA2019", "2019"},
+  { "MAYA2020", "2020"},
   { 0, 0 },
   { 0, 0 },
 };
 };
 
 
@@ -194,26 +195,22 @@ int
 main(int argc, char *argv[]) {
 main(int argc, char *argv[]) {
   // First, get the command line and append _bin, so we will actually run
   // First, get the command line and append _bin, so we will actually run
   // maya2egg_bin.exe, egg2maya_bin.exe, etc.
   // maya2egg_bin.exe, egg2maya_bin.exe, etc.
-  Filename command = Filename::from_os_specific(argv[0]);
-  if (!command.is_fully_qualified()) {
-    DSearchPath path;
-    path.append_path(ExecutionEnvironment::get_environment_variable("PATH"));
-#ifdef _WIN32
-    command.set_extension("exe");
-#endif
-    command.resolve_filename(path);
-  }
-
-#ifdef _WIN32
-  if (command.get_extension() == "exe") {
-    command.set_extension("");
+  Filename command = ExecutionEnvironment::get_binary_name();
+
+  if (command.empty() || command == "unknown" || !command.exists()) {
+    command = Filename::from_os_specific(argv[0]);
+
+    if (!command.is_fully_qualified()) {
+      DSearchPath path;
+      path.append_path(ExecutionEnvironment::get_environment_variable("PATH"));
+  #ifdef _WIN32
+      command.set_extension("exe");
+  #endif
+      command.resolve_filename(path);
+    }
   }
   }
-#endif
 
 
-  command = command.get_fullpath() + string("_bin");
-#ifdef _WIN32
-  command.set_extension("exe");
-#endif
+  command.set_basename_wo_extension(command.get_basename_wo_extension() + "_bin");
   string os_command = command.to_os_specific();
   string os_command = command.to_os_specific();
 
 
   // First start with $PANDA_MAYA_LOCATION.  If it is set, it overrides
   // First start with $PANDA_MAYA_LOCATION.  If it is set, it overrides

+ 36 - 0
tests/dcparser/test_dcpacker.py

@@ -0,0 +1,36 @@
+import pytest
+
+direct = pytest.importorskip("panda3d.direct")
+
+
+def test_pack_int8():
+    for num in range(-128, 128):
+        packer = direct.DCPacker()
+        packer.raw_pack_int8(num)
+        packer.set_unpack_data(packer.get_bytes())
+        assert packer.raw_unpack_int8() == num
+
+
+def test_pack_uint8():
+    for num in range(256):
+        packer = direct.DCPacker()
+        packer.raw_pack_uint8(num)
+        packer.set_unpack_data(packer.get_bytes())
+        assert packer.raw_unpack_uint8() == num
+
+
+def test_pack_int64():
+    for num in (0, -1, 0x7fffffff, -0x80000000, 0x7fffffffffffffff, 0x7ffffffffffffffe, -0x8000000000000000, -0x7fffffffffffffff):
+        packer = direct.DCPacker()
+        packer.raw_pack_int64(num)
+        packer.set_unpack_data(packer.get_bytes())
+        assert packer.raw_unpack_int64() == num
+
+
+def test_pack_uint64():
+    for num in (0, 1, 0x7fffffff, 0xffffffff, 0x7fffffffffffffff, 0xfffffffffffffffe, 0xffffffffffffffff):
+        packer = direct.DCPacker()
+        packer.raw_pack_uint64(num)
+        packer.set_unpack_data(packer.get_bytes())
+        assert packer.raw_unpack_uint64() == num
+