Browse Source

Merge branch 'master' of https://github.com/panda3d/panda3d

David Rose 9 years ago
parent
commit
63eb1636a9
100 changed files with 4477 additions and 1231 deletions
  1. 5 0
      .gitignore
  2. 0 9
      contrib/.gitignore
  3. 0 2
      contrib/src/panda3dtoolsgui/.gitignore
  4. 0 9
      direct/.gitignore
  5. 0 1
      direct/src/configfiles/.gitignore
  6. 0 3
      direct/src/dcparser/.gitignore
  7. 4 0
      direct/src/directscripts/eggcacher.py
  8. 3 0
      direct/src/directscripts/packpanda.py
  9. 1 5
      direct/src/distributed/DistributedObjectGlobalUD.py
  10. 3 3
      direct/src/distributed/cConnectionRepository.cxx
  11. 0 1
      direct/src/extensions_native/.gitignore
  12. 0 2
      direct/src/gui/.gitignore
  13. 3 3
      direct/src/gui/DirectScrolledList.py
  14. 0 8
      direct/src/p3d/.gitignore
  15. 0 1
      direct/src/plugin/.gitignore
  16. 0 1
      direct/src/plugin_activex/.gitignore
  17. 0 1
      direct/src/plugin_npapi/.gitignore
  18. 0 2
      direct/src/plugin_standalone/.gitignore
  19. 36 1
      direct/src/showbase/PythonUtil.py
  20. 0 1
      direct/src/showutil/.gitignore
  21. 0 7
      dmodels/.gitignore
  22. 0 6
      dmodels/src/.gitignore
  23. 10 0
      doc/ReleaseNotes
  24. 0 7
      dtool/.gitignore
  25. 0 2
      dtool/src/cppparser/.gitignore
  26. 10 1
      dtool/src/cppparser/cppArrayType.cxx
  27. 1 0
      dtool/src/cppparser/cppArrayType.h
  28. 551 482
      dtool/src/cppparser/cppBison.cxx.prebuilt
  29. 264 228
      dtool/src/cppparser/cppBison.h.prebuilt
  30. 339 18
      dtool/src/cppparser/cppBison.yxx
  31. 26 3
      dtool/src/cppparser/cppClassTemplateParameter.cxx
  32. 1 0
      dtool/src/cppparser/cppClassTemplateParameter.h
  33. 42 1
      dtool/src/cppparser/cppConstType.cxx
  34. 5 0
      dtool/src/cppparser/cppConstType.h
  35. 8 2
      dtool/src/cppparser/cppDeclaration.cxx
  36. 70 1
      dtool/src/cppparser/cppDeclaration.h
  37. 212 7
      dtool/src/cppparser/cppExpression.cxx
  38. 9 2
      dtool/src/cppparser/cppExpression.h
  39. 23 3
      dtool/src/cppparser/cppExtensionType.cxx
  40. 2 0
      dtool/src/cppparser/cppExtensionType.h
  41. 1 1
      dtool/src/cppparser/cppFile.h
  42. 14 6
      dtool/src/cppparser/cppFunctionType.cxx
  43. 4 1
      dtool/src/cppparser/cppFunctionType.h
  44. 8 5
      dtool/src/cppparser/cppInstance.cxx
  45. 3 0
      dtool/src/cppparser/cppInstance.h
  46. 7 7
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  47. 4 0
      dtool/src/cppparser/cppInstanceIdentifier.h
  48. 14 1
      dtool/src/cppparser/cppParser.cxx
  49. 65 0
      dtool/src/cppparser/cppPointerType.cxx
  50. 2 0
      dtool/src/cppparser/cppPointerType.h
  51. 257 83
      dtool/src/cppparser/cppPreprocessor.cxx
  52. 6 0
      dtool/src/cppparser/cppPreprocessor.h
  53. 79 0
      dtool/src/cppparser/cppReferenceType.cxx
  54. 3 0
      dtool/src/cppparser/cppReferenceType.h
  55. 1 1
      dtool/src/cppparser/cppScope.cxx
  56. 3 2
      dtool/src/cppparser/cppScope.h
  57. 53 0
      dtool/src/cppparser/cppSimpleType.cxx
  58. 11 7
      dtool/src/cppparser/cppSimpleType.h
  59. 379 39
      dtool/src/cppparser/cppStructType.cxx
  60. 12 0
      dtool/src/cppparser/cppStructType.h
  61. 4 2
      dtool/src/cppparser/cppTemplateScope.cxx
  62. 175 0
      dtool/src/cppparser/cppType.cxx
  63. 17 0
      dtool/src/cppparser/cppType.h
  64. 41 0
      dtool/src/cppparser/cppTypedefType.cxx
  65. 5 0
      dtool/src/cppparser/cppTypedefType.h
  66. 9 2
      dtool/src/dtoolbase/deletedBufferChain.cxx
  67. 1 5
      dtool/src/dtoolbase/deletedBufferChain.h
  68. 6 1
      dtool/src/dtoolbase/dtoolbase.h
  69. 16 4
      dtool/src/dtoolbase/memoryHook.I
  70. 5 0
      dtool/src/dtoolbase/memoryHook.cxx
  71. 2 0
      dtool/src/dtoolbase/neverFreeMemory.I
  72. 3 7
      dtool/src/dtoolbase/neverFreeMemory.cxx
  73. 0 3
      dtool/src/dtoolutil/.gitignore
  74. 15 10
      dtool/src/dtoolutil/filename.I
  75. 8 5
      dtool/src/dtoolutil/filename.h
  76. 4 2
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  77. 7 3
      dtool/src/interrogate/interrogateBuilder.cxx
  78. 153 0
      dtool/src/parser-inc/functional
  79. 34 0
      dtool/src/parser-inc/initializer_list
  80. 163 23
      dtool/src/parser-inc/memory
  81. 34 14
      dtool/src/parser-inc/stdint.h
  82. 2 0
      dtool/src/parser-inc/stdtypedefs.h
  83. 96 0
      dtool/src/parser-inc/type_traits
  84. 84 0
      dtool/src/parser-inc/unordered_map
  85. 83 0
      dtool/src/parser-inc/unordered_set
  86. 1 0
      dtool/src/parser-inc/xmmintrin.h
  87. 0 1
      dtool/src/prc/.gitignore
  88. 42 33
      dtool/src/prc/encryptStreamBuf.cxx
  89. 2 4
      dtool/src/prc/encryptStreamBuf.h
  90. 3 0
      dtool/src/prc/notify.cxx
  91. 4 0
      dtool/src/pystub/pystub.cxx
  92. 0 2
      makepanda/.gitignore
  93. 29 3
      makepanda/installer.nsi
  94. 196 115
      makepanda/makepanda.py
  95. 51 6
      makepanda/makepandacore.py
  96. 598 0
      makepanda/makewheel.py
  97. 0 8
      panda/.gitignore
  98. 1 1
      panda/src/audiotraits/openalAudioManager.h
  99. 1 1
      panda/src/audiotraits/openalAudioSound.h
  100. 28 0
      panda/src/bullet/bulletBodyNode.cxx

+ 5 - 0
.gitignore

@@ -45,3 +45,8 @@ CTestTestfile.cmake
 # Windows
 # Windows
 Thumbs.db
 Thumbs.db
 ehthumbs.db
 ehthumbs.db
+
+# Python
+__pycache__
+*.pyc
+*.pyo

+ 0 - 9
contrib/.gitignore

@@ -1,9 +0,0 @@
-*.pyc
-*.pyo
-/__init__.py
-# These are files that are generated within the source tree by the
-# ppremake system.
-Makefile
-pp.dep
-/built/
-Opt?-*

+ 0 - 2
contrib/src/panda3dtoolsgui/.gitignore

@@ -1,2 +0,0 @@
-/build
-/dist

+ 0 - 9
direct/.gitignore

@@ -1,9 +0,0 @@
-*.pyc
-*.pyo
-/__init__.py
-# These are files that are generated within the source tree by the
-# ppremake system.
-Makefile
-pp.dep
-/built/
-Opt?-*

+ 0 - 1
direct/src/configfiles/.gitignore

@@ -1 +0,0 @@
-/40_direct.prc

+ 0 - 3
direct/src/dcparser/.gitignore

@@ -1,3 +0,0 @@
-/dcLexer.cxx
-/dcParser.cxx
-/dcParser.h

+ 4 - 0
direct/src/directscripts/eggcacher.py

@@ -88,3 +88,7 @@ class EggCacher:
             progress += size
             progress += size
 
 
 cacher = EggCacher(sys.argv[1:])
 cacher = EggCacher(sys.argv[1:])
+
+# Dummy main function so this can be added to console_scripts.
+def main():
+    return 0

+ 3 - 0
direct/src/directscripts/packpanda.py

@@ -419,3 +419,6 @@ else:
     if not(os.path.exists("/usr/bin/rpmbuild") or os.path.exists("/usr/bin/dpkg-deb")):
     if not(os.path.exists("/usr/bin/rpmbuild") or os.path.exists("/usr/bin/dpkg-deb")):
         exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!")
         exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!")
 
 
+# Dummy main function so this can be added to console_scripts.
+def main():
+    return 0

+ 1 - 5
direct/src/distributed/DistributedObjectGlobalUD.py

@@ -26,11 +26,7 @@ class DistributedObjectGlobalUD(DistributedObjectUD):
 
 
     def execCommand(self, command, mwMgrId, avId, zoneId):
     def execCommand(self, command, mwMgrId, avId, zoneId):
         text = str(self.__execMessage(command))[:config.GetInt("ai-debug-length",300)]
         text = str(self.__execMessage(command))[:config.GetInt("ai-debug-length",300)]
-
-        dclass = uber.air.dclassesByName.get("PiratesMagicWordManagerAI")
-        dg = dclass.aiFormatUpdate(
-            "setMagicWordResponse", mwMgrId, (1<<32)+avId, uber.air.ourChannel, [text])
-        uber.air.send(dg)
+        self.notify.info(text)
 
 
     def __execMessage(self, message):
     def __execMessage(self, message):
         if not self.ExecNamespace:
         if not self.ExecNamespace:

+ 3 - 3
direct/src/distributed/cConnectionRepository.cxx

@@ -403,7 +403,7 @@ send_datagram(const Datagram &dg) {
 
 
 #ifdef WANT_NATIVE_NET
 #ifdef WANT_NATIVE_NET
   if (_native) {
   if (_native) {
-    bool result = _bdc.SendMessage();
+    bool result = _bdc.SendMessage(dg);
     if (!result && _bdc.IsConnected()) {
     if (!result && _bdc.IsConnected()) {
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
       ostringstream s;
       ostringstream s;
@@ -415,8 +415,8 @@ send_datagram(const Datagram &dg) {
 #endif
 #endif
 
 
       s << endl << "Error sending message: " << endl;
       s << endl << "Error sending message: " << endl;
-      msg.dump_hex(s);
-      s << "Message data: " << msg.get_data() << endl;
+      dg.dump_hex(s);
+      s << "Message data: " << dg.get_data() << endl;
 
 
       string message = s.str();
       string message = s.str();
       PyErr_SetString(exc_type, message.c_str());
       PyErr_SetString(exc_type, message.c_str());

+ 0 - 1
direct/src/extensions_native/.gitignore

@@ -1 +0,0 @@
-/extensions_darwin.py

+ 0 - 2
direct/src/gui/.gitignore

@@ -1,2 +0,0 @@
-/NL*
-/Nested*

+ 3 - 3
direct/src/gui/DirectScrolledList.py

@@ -20,7 +20,7 @@ class DirectScrolledListItem(DirectButton):
 
 
     def __init__(self, parent=None, **kw):
     def __init__(self, parent=None, **kw):
         assert self.notify.debugStateCall(self)
         assert self.notify.debugStateCall(self)
-        self.parent = parent
+        self._parent = parent
         if "command" in kw:
         if "command" in kw:
             self.nextCommand = kw.get("command")
             self.nextCommand = kw.get("command")
             del kw["command"]
             del kw["command"]
@@ -28,7 +28,7 @@ class DirectScrolledListItem(DirectButton):
             self.nextCommandExtraArgs = kw.get("extraArgs")
             self.nextCommandExtraArgs = kw.get("extraArgs")
             del kw["extraArgs"]
             del kw["extraArgs"]
         optiondefs = (
         optiondefs = (
-            ('parent', self.parent,    None),
+            ('parent', self._parent,    None),
             ('command', self.select, None),
             ('command', self.select, None),
             )
             )
         # Merge keyword options with default options
         # Merge keyword options with default options
@@ -39,7 +39,7 @@ class DirectScrolledListItem(DirectButton):
     def select(self):
     def select(self):
         assert self.notify.debugStateCall(self)
         assert self.notify.debugStateCall(self)
         self.nextCommand(*self.nextCommandExtraArgs)
         self.nextCommand(*self.nextCommandExtraArgs)
-        self.parent.selectListItem(self)
+        self._parent.selectListItem(self)
 
 
 
 
 class DirectScrolledList(DirectFrame):
 class DirectScrolledList(DirectFrame):

+ 0 - 8
direct/src/p3d/.gitignore

@@ -1,8 +0,0 @@
-/_vfsimporter.exp
-/_vfsimporter.lib
-/_vfsimporter.pyd
-/_vfsimporter.pyd.manifest
-/packp3d
-/ppackage
-/ppatcher
-/vc90.pdb

+ 0 - 1
direct/src/plugin/.gitignore

@@ -1 +0,0 @@
-/p3d_plugin_config.h

+ 0 - 1
direct/src/plugin_activex/.gitignore

@@ -1 +0,0 @@
-/P3DActiveX.rc

+ 0 - 1
direct/src/plugin_npapi/.gitignore

@@ -1 +0,0 @@
-/nppanda3d.rc

+ 0 - 2
direct/src/plugin_standalone/.gitignore

@@ -1,2 +0,0 @@
-/p3d_plugin_config.h
-/panda3d.rc

+ 36 - 1
direct/src/showbase/PythonUtil.py

@@ -38,7 +38,6 @@ import os
 import sys
 import sys
 import random
 import random
 import time
 import time
-import importlib
 
 
 __report_indent = 3
 __report_indent = 3
 
 
@@ -61,6 +60,42 @@ def Functor(function, *args, **kArgs):
     return functor
     return functor
 """
 """
 
 
+try:
+    import importlib
+except ImportError:
+    # Backward compatibility for Python 2.6.
+    def _resolve_name(name, package, level):
+        if not hasattr(package, 'rindex'):
+            raise ValueError("'package' not set to a string")
+        dot = len(package)
+        for x in xrange(level, 1, -1):
+            try:
+                dot = package.rindex('.', 0, dot)
+            except ValueError:
+                raise ValueError("attempted relative import beyond top-level "
+                                  "package")
+        return "%s.%s" % (package[:dot], name)
+
+    def import_module(name, package=None):
+        if name.startswith('.'):
+            if not package:
+                raise TypeError("relative imports require the 'package' argument")
+            level = 0
+            for character in name:
+                if character != '.':
+                    break
+                level += 1
+            name = _resolve_name(name[level:], package, level)
+        __import__(name)
+        return sys.modules[name]
+
+    imp = import_module('imp')
+    importlib = imp.new_module("importlib")
+    importlib._resolve_name = _resolve_name
+    importlib.import_module = import_module
+    sys.modules['importlib'] = importlib
+
+
 class Functor:
 class Functor:
     def __init__(self, function, *args, **kargs):
     def __init__(self, function, *args, **kargs):
         assert callable(function), "function should be a callable obj"
         assert callable(function), "function should be a callable obj"

+ 0 - 1
direct/src/showutil/.gitignore

@@ -1 +0,0 @@
-/runp3d

+ 0 - 7
dmodels/.gitignore

@@ -1,7 +0,0 @@
-*.egg
-*.pt
-/built/
-Makefile
-bams/
-optchar/
-pal_egg/

+ 0 - 6
dmodels/src/.gitignore

@@ -1,6 +0,0 @@
-/*.buildings
-/game_options.txt
-/prefixstrip
-/retarget/
-/textures.boo
-/topstrip/

+ 10 - 0
doc/ReleaseNotes

@@ -2,6 +2,7 @@
 
 
 This issue fixes several bugs that were still found in 1.9.2.
 This issue fixes several bugs that were still found in 1.9.2.
 
 
+* Fix crash when using homebrew Python on Mac OS X
 * Fix crash when running in Steam on Linux when using OpenAL
 * Fix crash when running in Steam on Linux when using OpenAL
 * Fix crash using wx/tkinter on Mac as long as want-wx/tk is set
 * Fix crash using wx/tkinter on Mac as long as want-wx/tk is set
 * Fix loading models from 'models' package with models/ prefix
 * Fix loading models from 'models' package with models/ prefix
@@ -45,6 +46,15 @@ This issue fixes several bugs that were still found in 1.9.2.
 * Fix rare X11 .ico cursor bug; also now supports PNG-compressed icons
 * Fix rare X11 .ico cursor bug; also now supports PNG-compressed icons
 * Add keyword argument support to make() methods such as Shader.make()
 * Add keyword argument support to make() methods such as Shader.make()
 * Fix compilation errors with Bullet 2.84
 * Fix compilation errors with Bullet 2.84
+* Fix exception when trying to pickle NodePathCollection objects
+* Fix error when trying to raise vectors to a power
+* GLSL: fix error when legacy matrix generator inputs are mat3
+* Now tries to preserve refresh rate when switching fullscreen on Windows
+* Fix back-to-front sorting when gl-coordinate-system is changed
+* Now also compiles on older Linux distros (eg. CentOS 5 / manylinux1)
+* get_keyboard_map now includes keys on layouts with special characters
+* Fix crash due to incorrect alignment when compiling Eigen with AVX
+* Fix crash when writing 16-bit .tif file (now silently downsamples)
 
 
 ------------------------  RELEASE 1.9.2  ------------------------
 ------------------------  RELEASE 1.9.2  ------------------------
 
 

+ 0 - 7
dtool/.gitignore

@@ -1,7 +0,0 @@
-/dtool_config.h
-# These are files that are generated within the source tree by the
-# ppremake system.
-Makefile
-pp.dep
-/built/
-Opt?-*

+ 0 - 2
dtool/src/cppparser/.gitignore

@@ -1,2 +0,0 @@
-/cppBison.cxx
-/cppBison.h

+ 10 - 1
dtool/src/cppparser/cppArrayType.cxx

@@ -13,6 +13,7 @@
 
 
 #include "cppArrayType.h"
 #include "cppArrayType.h"
 #include "cppExpression.h"
 #include "cppExpression.h"
+#include "cppPointerType.h"
 
 
 /**
 /**
  *
  *
@@ -63,6 +64,14 @@ is_tbd() const {
   return _element_type->is_tbd();
   return _element_type->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPArrayType::
+is_standard_layout() const {
+  return _element_type->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -76,7 +85,7 @@ is_trivial() const {
  */
  */
 bool CPPArrayType::
 bool CPPArrayType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return _element_type->is_default_constructible();
+  return _bounds != NULL && _element_type->is_default_constructible();
 }
 }
 
 
 /**
 /**

+ 1 - 0
dtool/src/cppparser/cppArrayType.h

@@ -38,6 +38,7 @@ public:
   virtual CPPType *resolve_type(CPPScope *current_scope,
   virtual CPPType *resolve_type(CPPScope *current_scope,
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;

File diff suppressed because it is too large
+ 551 - 482
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 264 - 228
dtool/src/cppparser/cppBison.h.prebuilt

@@ -54,120 +54,138 @@ extern int cppyydebug;
     CUSTOM_LITERAL = 264,
     CUSTOM_LITERAL = 264,
     IDENTIFIER = 265,
     IDENTIFIER = 265,
     TYPENAME_IDENTIFIER = 266,
     TYPENAME_IDENTIFIER = 266,
-    SCOPING = 267,
-    TYPEDEFNAME = 268,
-    ELLIPSIS = 269,
-    OROR = 270,
-    ANDAND = 271,
-    EQCOMPARE = 272,
-    NECOMPARE = 273,
-    LECOMPARE = 274,
-    GECOMPARE = 275,
-    LSHIFT = 276,
-    RSHIFT = 277,
-    POINTSAT_STAR = 278,
-    DOT_STAR = 279,
-    UNARY = 280,
-    UNARY_NOT = 281,
-    UNARY_NEGATE = 282,
-    UNARY_MINUS = 283,
-    UNARY_PLUS = 284,
-    UNARY_STAR = 285,
-    UNARY_REF = 286,
-    POINTSAT = 287,
-    SCOPE = 288,
-    PLUSPLUS = 289,
-    MINUSMINUS = 290,
-    TIMESEQUAL = 291,
-    DIVIDEEQUAL = 292,
-    MODEQUAL = 293,
-    PLUSEQUAL = 294,
-    MINUSEQUAL = 295,
-    OREQUAL = 296,
-    ANDEQUAL = 297,
-    XOREQUAL = 298,
-    LSHIFTEQUAL = 299,
-    RSHIFTEQUAL = 300,
-    KW_ALIGNAS = 301,
-    KW_ALIGNOF = 302,
-    KW_AUTO = 303,
-    KW_BEGIN_PUBLISH = 304,
-    KW_BLOCKING = 305,
-    KW_BOOL = 306,
-    KW_CATCH = 307,
-    KW_CHAR = 308,
-    KW_CHAR16_T = 309,
-    KW_CHAR32_T = 310,
-    KW_CLASS = 311,
-    KW_CONST = 312,
-    KW_CONSTEXPR = 313,
-    KW_CONST_CAST = 314,
-    KW_DECLTYPE = 315,
-    KW_DEFAULT = 316,
-    KW_DELETE = 317,
-    KW_DOUBLE = 318,
-    KW_DYNAMIC_CAST = 319,
-    KW_ELSE = 320,
-    KW_END_PUBLISH = 321,
-    KW_ENUM = 322,
-    KW_EXTENSION = 323,
-    KW_EXTERN = 324,
-    KW_EXPLICIT = 325,
-    KW_PUBLISHED = 326,
-    KW_FALSE = 327,
-    KW_FINAL = 328,
-    KW_FLOAT = 329,
-    KW_FRIEND = 330,
-    KW_FOR = 331,
-    KW_GOTO = 332,
-    KW_IF = 333,
-    KW_INLINE = 334,
-    KW_INT = 335,
-    KW_LONG = 336,
-    KW_MAKE_MAP_PROPERTY = 337,
-    KW_MAKE_PROPERTY = 338,
-    KW_MAKE_PROPERTY2 = 339,
-    KW_MAKE_SEQ = 340,
-    KW_MAKE_SEQ_PROPERTY = 341,
-    KW_MUTABLE = 342,
-    KW_NAMESPACE = 343,
-    KW_NEW = 344,
-    KW_NOEXCEPT = 345,
-    KW_NULLPTR = 346,
-    KW_OPERATOR = 347,
-    KW_OVERRIDE = 348,
-    KW_PRIVATE = 349,
-    KW_PROTECTED = 350,
-    KW_PUBLIC = 351,
-    KW_REGISTER = 352,
-    KW_REINTERPRET_CAST = 353,
-    KW_RETURN = 354,
-    KW_SHORT = 355,
-    KW_SIGNED = 356,
-    KW_SIZEOF = 357,
-    KW_STATIC = 358,
-    KW_STATIC_ASSERT = 359,
-    KW_STATIC_CAST = 360,
-    KW_STRUCT = 361,
-    KW_TEMPLATE = 362,
-    KW_THREAD_LOCAL = 363,
-    KW_THROW = 364,
-    KW_TRUE = 365,
-    KW_TRY = 366,
-    KW_TYPEDEF = 367,
-    KW_TYPEID = 368,
-    KW_TYPENAME = 369,
-    KW_UNION = 370,
-    KW_UNSIGNED = 371,
-    KW_USING = 372,
-    KW_VIRTUAL = 373,
-    KW_VOID = 374,
-    KW_VOLATILE = 375,
-    KW_WCHAR_T = 376,
-    KW_WHILE = 377,
-    START_CPP = 378,
-    START_CONST_EXPR = 379,
-    START_TYPE = 380
+    TYPEPACK_IDENTIFIER = 267,
+    SCOPING = 268,
+    TYPEDEFNAME = 269,
+    ELLIPSIS = 270,
+    OROR = 271,
+    ANDAND = 272,
+    EQCOMPARE = 273,
+    NECOMPARE = 274,
+    LECOMPARE = 275,
+    GECOMPARE = 276,
+    LSHIFT = 277,
+    RSHIFT = 278,
+    POINTSAT_STAR = 279,
+    DOT_STAR = 280,
+    UNARY = 281,
+    UNARY_NOT = 282,
+    UNARY_NEGATE = 283,
+    UNARY_MINUS = 284,
+    UNARY_PLUS = 285,
+    UNARY_STAR = 286,
+    UNARY_REF = 287,
+    POINTSAT = 288,
+    SCOPE = 289,
+    PLUSPLUS = 290,
+    MINUSMINUS = 291,
+    TIMESEQUAL = 292,
+    DIVIDEEQUAL = 293,
+    MODEQUAL = 294,
+    PLUSEQUAL = 295,
+    MINUSEQUAL = 296,
+    OREQUAL = 297,
+    ANDEQUAL = 298,
+    XOREQUAL = 299,
+    LSHIFTEQUAL = 300,
+    RSHIFTEQUAL = 301,
+    KW_ALIGNAS = 302,
+    KW_ALIGNOF = 303,
+    KW_AUTO = 304,
+    KW_BEGIN_PUBLISH = 305,
+    KW_BLOCKING = 306,
+    KW_BOOL = 307,
+    KW_CATCH = 308,
+    KW_CHAR = 309,
+    KW_CHAR16_T = 310,
+    KW_CHAR32_T = 311,
+    KW_CLASS = 312,
+    KW_CONST = 313,
+    KW_CONSTEXPR = 314,
+    KW_CONST_CAST = 315,
+    KW_DECLTYPE = 316,
+    KW_DEFAULT = 317,
+    KW_DELETE = 318,
+    KW_DOUBLE = 319,
+    KW_DYNAMIC_CAST = 320,
+    KW_ELSE = 321,
+    KW_END_PUBLISH = 322,
+    KW_ENUM = 323,
+    KW_EXTENSION = 324,
+    KW_EXTERN = 325,
+    KW_EXPLICIT = 326,
+    KW_PUBLISHED = 327,
+    KW_FALSE = 328,
+    KW_FINAL = 329,
+    KW_FLOAT = 330,
+    KW_FRIEND = 331,
+    KW_FOR = 332,
+    KW_GOTO = 333,
+    KW_HAS_VIRTUAL_DESTRUCTOR = 334,
+    KW_IF = 335,
+    KW_INLINE = 336,
+    KW_INT = 337,
+    KW_IS_ABSTRACT = 338,
+    KW_IS_BASE_OF = 339,
+    KW_IS_CLASS = 340,
+    KW_IS_CONSTRUCTIBLE = 341,
+    KW_IS_CONVERTIBLE_TO = 342,
+    KW_IS_DESTRUCTIBLE = 343,
+    KW_IS_EMPTY = 344,
+    KW_IS_ENUM = 345,
+    KW_IS_FINAL = 346,
+    KW_IS_FUNDAMENTAL = 347,
+    KW_IS_POD = 348,
+    KW_IS_POLYMORPHIC = 349,
+    KW_IS_STANDARD_LAYOUT = 350,
+    KW_IS_TRIVIAL = 351,
+    KW_IS_UNION = 352,
+    KW_LONG = 353,
+    KW_MAKE_MAP_PROPERTY = 354,
+    KW_MAKE_PROPERTY = 355,
+    KW_MAKE_PROPERTY2 = 356,
+    KW_MAKE_SEQ = 357,
+    KW_MAKE_SEQ_PROPERTY = 358,
+    KW_MUTABLE = 359,
+    KW_NAMESPACE = 360,
+    KW_NEW = 361,
+    KW_NOEXCEPT = 362,
+    KW_NULLPTR = 363,
+    KW_OPERATOR = 364,
+    KW_OVERRIDE = 365,
+    KW_PRIVATE = 366,
+    KW_PROTECTED = 367,
+    KW_PUBLIC = 368,
+    KW_REGISTER = 369,
+    KW_REINTERPRET_CAST = 370,
+    KW_RETURN = 371,
+    KW_SHORT = 372,
+    KW_SIGNED = 373,
+    KW_SIZEOF = 374,
+    KW_STATIC = 375,
+    KW_STATIC_ASSERT = 376,
+    KW_STATIC_CAST = 377,
+    KW_STRUCT = 378,
+    KW_TEMPLATE = 379,
+    KW_THREAD_LOCAL = 380,
+    KW_THROW = 381,
+    KW_TRUE = 382,
+    KW_TRY = 383,
+    KW_TYPEDEF = 384,
+    KW_TYPEID = 385,
+    KW_TYPENAME = 386,
+    KW_UNDERLYING_TYPE = 387,
+    KW_UNION = 388,
+    KW_UNSIGNED = 389,
+    KW_USING = 390,
+    KW_VIRTUAL = 391,
+    KW_VOID = 392,
+    KW_VOLATILE = 393,
+    KW_WCHAR_T = 394,
+    KW_WHILE = 395,
+    START_CPP = 396,
+    START_CONST_EXPR = 397,
+    START_TYPE = 398
   };
   };
 #endif
 #endif
 /* Tokens.  */
 /* Tokens.  */
@@ -180,120 +198,138 @@ extern int cppyydebug;
 #define CUSTOM_LITERAL 264
 #define CUSTOM_LITERAL 264
 #define IDENTIFIER 265
 #define IDENTIFIER 265
 #define TYPENAME_IDENTIFIER 266
 #define TYPENAME_IDENTIFIER 266
-#define SCOPING 267
-#define TYPEDEFNAME 268
-#define ELLIPSIS 269
-#define OROR 270
-#define ANDAND 271
-#define EQCOMPARE 272
-#define NECOMPARE 273
-#define LECOMPARE 274
-#define GECOMPARE 275
-#define LSHIFT 276
-#define RSHIFT 277
-#define POINTSAT_STAR 278
-#define DOT_STAR 279
-#define UNARY 280
-#define UNARY_NOT 281
-#define UNARY_NEGATE 282
-#define UNARY_MINUS 283
-#define UNARY_PLUS 284
-#define UNARY_STAR 285
-#define UNARY_REF 286
-#define POINTSAT 287
-#define SCOPE 288
-#define PLUSPLUS 289
-#define MINUSMINUS 290
-#define TIMESEQUAL 291
-#define DIVIDEEQUAL 292
-#define MODEQUAL 293
-#define PLUSEQUAL 294
-#define MINUSEQUAL 295
-#define OREQUAL 296
-#define ANDEQUAL 297
-#define XOREQUAL 298
-#define LSHIFTEQUAL 299
-#define RSHIFTEQUAL 300
-#define KW_ALIGNAS 301
-#define KW_ALIGNOF 302
-#define KW_AUTO 303
-#define KW_BEGIN_PUBLISH 304
-#define KW_BLOCKING 305
-#define KW_BOOL 306
-#define KW_CATCH 307
-#define KW_CHAR 308
-#define KW_CHAR16_T 309
-#define KW_CHAR32_T 310
-#define KW_CLASS 311
-#define KW_CONST 312
-#define KW_CONSTEXPR 313
-#define KW_CONST_CAST 314
-#define KW_DECLTYPE 315
-#define KW_DEFAULT 316
-#define KW_DELETE 317
-#define KW_DOUBLE 318
-#define KW_DYNAMIC_CAST 319
-#define KW_ELSE 320
-#define KW_END_PUBLISH 321
-#define KW_ENUM 322
-#define KW_EXTENSION 323
-#define KW_EXTERN 324
-#define KW_EXPLICIT 325
-#define KW_PUBLISHED 326
-#define KW_FALSE 327
-#define KW_FINAL 328
-#define KW_FLOAT 329
-#define KW_FRIEND 330
-#define KW_FOR 331
-#define KW_GOTO 332
-#define KW_IF 333
-#define KW_INLINE 334
-#define KW_INT 335
-#define KW_LONG 336
-#define KW_MAKE_MAP_PROPERTY 337
-#define KW_MAKE_PROPERTY 338
-#define KW_MAKE_PROPERTY2 339
-#define KW_MAKE_SEQ 340
-#define KW_MAKE_SEQ_PROPERTY 341
-#define KW_MUTABLE 342
-#define KW_NAMESPACE 343
-#define KW_NEW 344
-#define KW_NOEXCEPT 345
-#define KW_NULLPTR 346
-#define KW_OPERATOR 347
-#define KW_OVERRIDE 348
-#define KW_PRIVATE 349
-#define KW_PROTECTED 350
-#define KW_PUBLIC 351
-#define KW_REGISTER 352
-#define KW_REINTERPRET_CAST 353
-#define KW_RETURN 354
-#define KW_SHORT 355
-#define KW_SIGNED 356
-#define KW_SIZEOF 357
-#define KW_STATIC 358
-#define KW_STATIC_ASSERT 359
-#define KW_STATIC_CAST 360
-#define KW_STRUCT 361
-#define KW_TEMPLATE 362
-#define KW_THREAD_LOCAL 363
-#define KW_THROW 364
-#define KW_TRUE 365
-#define KW_TRY 366
-#define KW_TYPEDEF 367
-#define KW_TYPEID 368
-#define KW_TYPENAME 369
-#define KW_UNION 370
-#define KW_UNSIGNED 371
-#define KW_USING 372
-#define KW_VIRTUAL 373
-#define KW_VOID 374
-#define KW_VOLATILE 375
-#define KW_WCHAR_T 376
-#define KW_WHILE 377
-#define START_CPP 378
-#define START_CONST_EXPR 379
-#define START_TYPE 380
+#define TYPEPACK_IDENTIFIER 267
+#define SCOPING 268
+#define TYPEDEFNAME 269
+#define ELLIPSIS 270
+#define OROR 271
+#define ANDAND 272
+#define EQCOMPARE 273
+#define NECOMPARE 274
+#define LECOMPARE 275
+#define GECOMPARE 276
+#define LSHIFT 277
+#define RSHIFT 278
+#define POINTSAT_STAR 279
+#define DOT_STAR 280
+#define UNARY 281
+#define UNARY_NOT 282
+#define UNARY_NEGATE 283
+#define UNARY_MINUS 284
+#define UNARY_PLUS 285
+#define UNARY_STAR 286
+#define UNARY_REF 287
+#define POINTSAT 288
+#define SCOPE 289
+#define PLUSPLUS 290
+#define MINUSMINUS 291
+#define TIMESEQUAL 292
+#define DIVIDEEQUAL 293
+#define MODEQUAL 294
+#define PLUSEQUAL 295
+#define MINUSEQUAL 296
+#define OREQUAL 297
+#define ANDEQUAL 298
+#define XOREQUAL 299
+#define LSHIFTEQUAL 300
+#define RSHIFTEQUAL 301
+#define KW_ALIGNAS 302
+#define KW_ALIGNOF 303
+#define KW_AUTO 304
+#define KW_BEGIN_PUBLISH 305
+#define KW_BLOCKING 306
+#define KW_BOOL 307
+#define KW_CATCH 308
+#define KW_CHAR 309
+#define KW_CHAR16_T 310
+#define KW_CHAR32_T 311
+#define KW_CLASS 312
+#define KW_CONST 313
+#define KW_CONSTEXPR 314
+#define KW_CONST_CAST 315
+#define KW_DECLTYPE 316
+#define KW_DEFAULT 317
+#define KW_DELETE 318
+#define KW_DOUBLE 319
+#define KW_DYNAMIC_CAST 320
+#define KW_ELSE 321
+#define KW_END_PUBLISH 322
+#define KW_ENUM 323
+#define KW_EXTENSION 324
+#define KW_EXTERN 325
+#define KW_EXPLICIT 326
+#define KW_PUBLISHED 327
+#define KW_FALSE 328
+#define KW_FINAL 329
+#define KW_FLOAT 330
+#define KW_FRIEND 331
+#define KW_FOR 332
+#define KW_GOTO 333
+#define KW_HAS_VIRTUAL_DESTRUCTOR 334
+#define KW_IF 335
+#define KW_INLINE 336
+#define KW_INT 337
+#define KW_IS_ABSTRACT 338
+#define KW_IS_BASE_OF 339
+#define KW_IS_CLASS 340
+#define KW_IS_CONSTRUCTIBLE 341
+#define KW_IS_CONVERTIBLE_TO 342
+#define KW_IS_DESTRUCTIBLE 343
+#define KW_IS_EMPTY 344
+#define KW_IS_ENUM 345
+#define KW_IS_FINAL 346
+#define KW_IS_FUNDAMENTAL 347
+#define KW_IS_POD 348
+#define KW_IS_POLYMORPHIC 349
+#define KW_IS_STANDARD_LAYOUT 350
+#define KW_IS_TRIVIAL 351
+#define KW_IS_UNION 352
+#define KW_LONG 353
+#define KW_MAKE_MAP_PROPERTY 354
+#define KW_MAKE_PROPERTY 355
+#define KW_MAKE_PROPERTY2 356
+#define KW_MAKE_SEQ 357
+#define KW_MAKE_SEQ_PROPERTY 358
+#define KW_MUTABLE 359
+#define KW_NAMESPACE 360
+#define KW_NEW 361
+#define KW_NOEXCEPT 362
+#define KW_NULLPTR 363
+#define KW_OPERATOR 364
+#define KW_OVERRIDE 365
+#define KW_PRIVATE 366
+#define KW_PROTECTED 367
+#define KW_PUBLIC 368
+#define KW_REGISTER 369
+#define KW_REINTERPRET_CAST 370
+#define KW_RETURN 371
+#define KW_SHORT 372
+#define KW_SIGNED 373
+#define KW_SIZEOF 374
+#define KW_STATIC 375
+#define KW_STATIC_ASSERT 376
+#define KW_STATIC_CAST 377
+#define KW_STRUCT 378
+#define KW_TEMPLATE 379
+#define KW_THREAD_LOCAL 380
+#define KW_THROW 381
+#define KW_TRUE 382
+#define KW_TRY 383
+#define KW_TYPEDEF 384
+#define KW_TYPEID 385
+#define KW_TYPENAME 386
+#define KW_UNDERLYING_TYPE 387
+#define KW_UNION 388
+#define KW_UNSIGNED 389
+#define KW_USING 390
+#define KW_VIRTUAL 391
+#define KW_VOID 392
+#define KW_VOLATILE 393
+#define KW_WCHAR_T 394
+#define KW_WHILE 395
+#define START_CPP 396
+#define START_CONST_EXPR 397
+#define START_TYPE 398
 
 
 /* Value type.  */
 /* Value type.  */
 
 

+ 339 - 18
dtool/src/cppparser/cppBison.yxx

@@ -212,7 +212,7 @@ pop_struct() {
 %token <u.integer> CHAR_TOK
 %token <u.integer> CHAR_TOK
 %token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
 %token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
 %token <u.expr> STRING_LITERAL CUSTOM_LITERAL
 %token <u.expr> STRING_LITERAL CUSTOM_LITERAL
-%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER SCOPING
+%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER TYPEPACK_IDENTIFIER SCOPING
 %token <u.type> TYPEDEFNAME
 %token <u.type> TYPEDEFNAME
 
 
 %token ELLIPSIS
 %token ELLIPSIS
@@ -280,9 +280,25 @@ pop_struct() {
 %token KW_FRIEND
 %token KW_FRIEND
 %token KW_FOR
 %token KW_FOR
 %token KW_GOTO
 %token KW_GOTO
+%token KW_HAS_VIRTUAL_DESTRUCTOR
 %token KW_IF
 %token KW_IF
 %token KW_INLINE
 %token KW_INLINE
 %token KW_INT
 %token KW_INT
+%token KW_IS_ABSTRACT
+%token KW_IS_BASE_OF
+%token KW_IS_CLASS
+%token KW_IS_CONSTRUCTIBLE
+%token KW_IS_CONVERTIBLE_TO
+%token KW_IS_DESTRUCTIBLE
+%token KW_IS_EMPTY
+%token KW_IS_ENUM
+%token KW_IS_FINAL
+%token KW_IS_FUNDAMENTAL
+%token KW_IS_POD
+%token KW_IS_POLYMORPHIC
+%token KW_IS_STANDARD_LAYOUT
+%token KW_IS_TRIVIAL
+%token KW_IS_UNION
 %token KW_LONG
 %token KW_LONG
 %token KW_MAKE_MAP_PROPERTY
 %token KW_MAKE_MAP_PROPERTY
 %token KW_MAKE_PROPERTY
 %token KW_MAKE_PROPERTY
@@ -317,6 +333,7 @@ pop_struct() {
 %token KW_TYPEDEF
 %token KW_TYPEDEF
 %token KW_TYPEID
 %token KW_TYPEID
 %token KW_TYPENAME
 %token KW_TYPENAME
+%token KW_UNDERLYING_TYPE
 %token KW_UNION
 %token KW_UNION
 %token KW_UNSIGNED
 %token KW_UNSIGNED
 %token KW_USING
 %token KW_USING
@@ -354,9 +371,10 @@ pop_struct() {
 %type <u.instance> formal_parameter
 %type <u.instance> formal_parameter
 %type <u.inst_ident> not_paren_formal_parameter_identifier
 %type <u.inst_ident> not_paren_formal_parameter_identifier
 %type <u.inst_ident> formal_parameter_identifier
 %type <u.inst_ident> formal_parameter_identifier
+%type <u.inst_ident> parameter_pack_identifier
 %type <u.inst_ident> not_paren_empty_instance_identifier
 %type <u.inst_ident> not_paren_empty_instance_identifier
 %type <u.inst_ident> empty_instance_identifier
 %type <u.inst_ident> empty_instance_identifier
-%type <u.type> type
+%type <u.type> type type_pack
 %type <u.decl> type_decl
 %type <u.decl> type_decl
 %type <u.decl> var_type_decl
 %type <u.decl> var_type_decl
 %type <u.type> predefined_type
 %type <u.type> predefined_type
@@ -447,6 +465,10 @@ constructor_init:
         name '(' optional_const_expr_comma ')'
         name '(' optional_const_expr_comma ')'
 {
 {
   delete $3;
   delete $3;
+}
+        | name '(' optional_const_expr_comma ')' ELLIPSIS
+{
+  delete $3;
 }
 }
         | name '{' optional_const_expr_comma '}'
         | name '{' optional_const_expr_comma '}'
 {
 {
@@ -1187,26 +1209,38 @@ function_post:
 {
 {
   $$ = 0;
   $$ = 0;
 }
 }
-        | KW_CONST
+        | function_post KW_CONST
 {
 {
-  $$ = (int)CPPFunctionType::F_const_method;
+  $$ = $1 | (int)CPPFunctionType::F_const_method;
+}
+        | function_post KW_VOLATILE
+{
+  $$ = $1 | (int)CPPFunctionType::F_volatile_method;
 }
 }
         | function_post KW_NOEXCEPT
         | function_post KW_NOEXCEPT
 {
 {
-  $$ = (int)CPPFunctionType::F_noexcept;
+  $$ = $1 | (int)CPPFunctionType::F_noexcept;
 }
 }
         | function_post KW_FINAL
         | function_post KW_FINAL
 {
 {
-  $$ = (int)CPPFunctionType::F_final;
+  $$ = $1 | (int)CPPFunctionType::F_final;
 }
 }
         | function_post KW_OVERRIDE
         | function_post KW_OVERRIDE
 {
 {
-  $$ = (int)CPPFunctionType::F_override;
+  $$ = $1 | (int)CPPFunctionType::F_override;
+}
+        | function_post '&'
+{
+  $$ = $1 | (int)CPPFunctionType::F_lvalue_method;
+}
+        | function_post ANDAND
+{
+  $$ = $1 | (int)CPPFunctionType::F_rvalue_method;
 }
 }
         | function_post KW_MUTABLE
         | function_post KW_MUTABLE
 {
 {
   // Used for lambdas, currently ignored.
   // Used for lambdas, currently ignored.
-  $$ = 0;
+  $$ = $1;
 }
 }
         | function_post KW_THROW '(' ')'
         | function_post KW_THROW '(' ')'
 {
 {
@@ -1215,6 +1249,10 @@ function_post:
         | function_post KW_THROW '(' name ')'
         | function_post KW_THROW '(' name ')'
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | function_post KW_THROW '(' name ELLIPSIS ')'
+{
+  $$ = $1;
 }
 }
 /*        | function_post '[' '[' attribute_specifiers ']' ']'
 /*        | function_post '[' '[' attribute_specifiers ']' ']'
 {
 {
@@ -1418,22 +1456,35 @@ template_nonempty_formal_parameters:
 }
 }
         ;
         ;
 
 
+typename_keyword:
+        KW_CLASS
+        | KW_TYPENAME
+        ;
+
 template_formal_parameter:
 template_formal_parameter:
-        KW_CLASS name
+        typename_keyword
+{
+  $$ = CPPType::new_type(new CPPClassTemplateParameter((CPPIdentifier *)NULL));
+}
+        | typename_keyword name
 {
 {
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
 }
 }
-        | KW_CLASS name '=' full_type
+        | typename_keyword name '=' full_type
 {
 {
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
   $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
 }
 }
-        | KW_TYPENAME name
+        | typename_keyword ELLIPSIS
 {
 {
-  $$ = CPPType::new_type(new CPPClassTemplateParameter($2));
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter((CPPIdentifier *)NULL);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
-        | KW_TYPENAME name '=' full_type
+        | typename_keyword ELLIPSIS name
 {
 {
-  $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4));
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($3);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
         | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
         | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize
 {
 {
@@ -1447,6 +1498,17 @@ template_formal_parameter:
   CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
   CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
   inst->set_initializer($4);
   inst->set_initializer($4);
   $$ = inst;
   $$ = inst;
+}
+        | template_formal_parameter_type parameter_pack_identifier
+{
+  CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file);
+  $$ = inst;
+}
+        | KW_CONST template_formal_parameter_type parameter_pack_identifier
+{
+  $3->add_modifier(IIT_const);
+  CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file);
+  $$ = inst;
 }
 }
         ;
         ;
 
 
@@ -1467,6 +1529,14 @@ template_formal_parameter_type:
     yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
     yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
   }
   }
   assert($$ != NULL);
   assert($$ != NULL);
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
+  if ($$ == NULL) {
+    yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
+  }
+  assert($$ != NULL);
 }
 }
         ;
         ;
 
 
@@ -1547,7 +1617,16 @@ instance_identifier:
 }
 }
         | instance_identifier '('
         | instance_identifier '('
 {
 {
-  push_scope($1->get_scope(current_scope, global_scope));
+  // Create a scope for this function (in case it is a function)
+  CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope),
+                                 CPPNameComponent(""), V_private);
+
+  // It still needs to be able to pick up any template arguments, if this is
+  // a definition for a method template.  Add a fake "using" declaration to
+  // accomplish this.
+  scope->_using.insert(current_scope);
+
+  push_scope(scope);
 }
 }
         formal_parameter_list ')' function_post
         formal_parameter_list ')' function_post
 {
 {
@@ -1785,6 +1864,23 @@ function_parameter:
   $4->add_modifier(IIT_const);
   $4->add_modifier(IIT_const);
   $$ = new CPPInstance($3, $4, 0, @3.file);
   $$ = new CPPInstance($3, $4, 0, @3.file);
   $$->set_initializer($5);
   $$->set_initializer($5);
+}
+        | type_pack parameter_pack_identifier maybe_initialize
+{
+  $$ = new CPPInstance($1, $2, 0, @2.file);
+  $$->set_initializer($3);
+}
+        | KW_CONST type_pack parameter_pack_identifier maybe_initialize
+{
+  $3->add_modifier(IIT_const);
+  $$ = new CPPInstance($2, $3, 0, @3.file);
+  $$->set_initializer($4);
+}
+        | KW_CONST KW_REGISTER type_pack parameter_pack_identifier maybe_initialize
+{
+  $4->add_modifier(IIT_const);
+  $$ = new CPPInstance($3, $4, 0, @3.file);
+  $$->set_initializer($5);
 }
 }
         | KW_REGISTER function_parameter
         | KW_REGISTER function_parameter
 {
 {
@@ -1913,10 +2009,79 @@ formal_parameter_identifier:
 }
 }
         ;
         ;
 
 
+parameter_pack_identifier:
+        ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
+}
+        | KW_CONST parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_const);
+}
+        | KW_VOLATILE parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_volatile);
+}
+        | '*' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_pointer);
+}
+        | '&' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_reference);
+}
+        | ANDAND parameter_pack_identifier  %prec UNARY
+{
+  $$ = $2;
+  $$->add_modifier(IIT_rvalue_reference);
+}
+        | SCOPING '*' parameter_pack_identifier  %prec UNARY
+{
+  $$ = $3;
+  $$->add_scoped_pointer_modifier($1);
+}
+        | parameter_pack_identifier '[' optional_const_expr ']'
+{
+  $$ = $1;
+  $$->add_array_modifier($3);
+}
+        | '(' parameter_pack_identifier ')' '(' function_parameter_list ')' function_post
+{
+  $$ = $2;
+  $$->add_modifier(IIT_paren);
+  $$->add_func_modifier($5, $7);
+}
+        | '(' parameter_pack_identifier ')'
+{
+  $$ = $2;
+  $$->add_modifier(IIT_paren);
+}
+        ;
+
 not_paren_empty_instance_identifier:
 not_paren_empty_instance_identifier:
         empty
         empty
 {
 {
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+}
+        | ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
 }
 }
         | KW_CONST not_paren_empty_instance_identifier  %prec UNARY
         | KW_CONST not_paren_empty_instance_identifier  %prec UNARY
 {
 {
@@ -1959,6 +2124,16 @@ empty_instance_identifier:
         empty
         empty
 {
 {
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
   $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+}
+        | ELLIPSIS
+{
+  $$ = new CPPInstanceIdentifier((CPPIdentifier *)NULL);
+  $$->_packed = true;
+}
+        | ELLIPSIS name
+{
+  $$ = new CPPInstanceIdentifier($2);
+  $$->_packed = true;
 }
 }
         | KW_CONST empty_instance_identifier  %prec UNARY
         | KW_CONST empty_instance_identifier  %prec UNARY
 {
 {
@@ -2093,6 +2268,16 @@ type:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2100,6 +2285,17 @@ type:
 }
 }
         ;
         ;
 
 
+type_pack:
+        TYPEPACK_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
+  if ($$ == NULL) {
+    yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
+  }
+  assert($$ != NULL);
+}
+        ;
+
 type_decl:
 type_decl:
         simple_type
         simple_type
 {
 {
@@ -2187,6 +2383,16 @@ type_decl:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2251,6 +2457,16 @@ predefined_type:
     str << *$3;
     str << *$3;
     yyerror("could not determine type of " + str.str(), @3);
     yyerror("could not determine type of " + str.str(), @3);
   }
   }
+}
+        | KW_UNDERLYING_TYPE '(' full_type ')'
+{
+  CPPEnumType *enum_type = $3->as_enum_type();
+  if (enum_type == NULL) {
+    yyerror("an enumeration type is required", @3);
+    $$ = $3;
+  } else {
+    $$ = enum_type->get_underlying_type();
+  }
 }
 }
         | KW_AUTO
         | KW_AUTO
 {
 {
@@ -2279,6 +2495,15 @@ full_type:
 {
 {
   $3->add_modifier(IIT_const);
   $3->add_modifier(IIT_const);
   $$ = $3->unroll_type($2);
   $$ = $3->unroll_type($2);
+}
+        | type_pack empty_instance_identifier
+{
+  $$ = $2->unroll_type($1);
+}
+        | KW_CONST type_pack empty_instance_identifier
+{
+  $3->add_modifier(IIT_const);
+  $$ = $3->unroll_type($2);
 }
 }
         ;
         ;
 
 
@@ -2693,6 +2918,7 @@ element:
         | CHAR_TOK
         | CHAR_TOK
         | IDENTIFIER
         | IDENTIFIER
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
+        | TYPEPACK_IDENTIFIER
         | SCOPING
         | SCOPING
         | SIMPLE_IDENTIFIER
         | SIMPLE_IDENTIFIER
         | ELLIPSIS | OROR | ANDAND
         | ELLIPSIS | OROR | ANDAND
@@ -2711,10 +2937,11 @@ element:
         | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED
         | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED
         | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST
         | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST
         | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC
         | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC
-        | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT
+        | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT | KW_TEMPLATE
         | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF
         | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF
-        | KW_TYPEID | KW_TYPENAME | KW_UNION | KW_UNSIGNED | KW_USING
-        | KW_VIRTUAL | KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE
+        | KW_TYPEID | KW_TYPENAME | KW_UNDERLYING_TYPE | KW_UNION
+        | KW_UNSIGNED | KW_USING | KW_VIRTUAL | KW_VOID | KW_VOLATILE
+        | KW_WCHAR_T | KW_WHILE
 {
 {
 }
 }
         | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
         | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
@@ -2783,6 +3010,10 @@ no_angle_bracket_const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3021,6 +3252,10 @@ const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3238,6 +3473,74 @@ const_operand:
         | '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}'
         | '[' capture_list ']' '(' function_parameter_list ')' function_post maybe_trailing_return_type '{' code '}'
 {
 {
   $$ = NULL;
   $$ = NULL;
+}
+        | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_HAS_VIRTUAL_DESTRUCTOR, $3));
+}
+        | KW_IS_ABSTRACT '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ABSTRACT, $3));
+}
+        | KW_IS_BASE_OF '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3, $5));
+}
+        | KW_IS_CLASS '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3));
+}
+        | KW_IS_CONSTRUCTIBLE '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3));
+}
+        | KW_IS_CONSTRUCTIBLE '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3, $5));
+}
+        | KW_IS_CONVERTIBLE_TO '(' full_type ',' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONVERTIBLE_TO, $3, $5));
+}
+        | KW_IS_DESTRUCTIBLE '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_DESTRUCTIBLE, $3));
+}
+        | KW_IS_EMPTY '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_EMPTY, $3));
+}
+        | KW_IS_ENUM '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ENUM, $3));
+}
+        | KW_IS_FINAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FINAL, $3));
+}
+        | KW_IS_FUNDAMENTAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FUNDAMENTAL, $3));
+}
+        | KW_IS_POD '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POD, $3));
+}
+        | KW_IS_POLYMORPHIC '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POLYMORPHIC, $3));
+}
+        | KW_IS_STANDARD_LAYOUT '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_STANDARD_LAYOUT, $3));
+}
+        | KW_IS_TRIVIAL '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIAL, $3));
+}
+        | KW_IS_UNION '(' full_type ')'
+{
+  $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_UNION, $3));
 }
 }
         ;
         ;
 
 
@@ -3276,6 +3579,10 @@ formal_const_expr:
         | KW_SIZEOF '(' full_type ')' %prec UNARY
         | KW_SIZEOF '(' full_type ')' %prec UNARY
 {
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
+}
+        | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
+{
+  $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4));
 }
 }
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
         | KW_ALIGNOF '(' full_type ')' %prec UNARY
 {
 {
@@ -3518,6 +3825,12 @@ class_derivation_name:
         | KW_TYPENAME name
         | KW_TYPENAME name
 {
 {
   $$ = CPPType::new_type(new CPPTBDType($2));
   $$ = CPPType::new_type(new CPPTBDType($2));
+}
+        | name ELLIPSIS
+{
+  CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($1);
+  ctp->_packed = true;
+  $$ = CPPType::new_type(ctp);
 }
 }
         ;
         ;
 
 
@@ -3550,6 +3863,10 @@ name:
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1;
 }
 }
         | KW_FINAL
         | KW_FINAL
 {
 {
@@ -3595,6 +3912,10 @@ name_no_final:
         | TYPENAME_IDENTIFIER
         | TYPENAME_IDENTIFIER
 {
 {
   $$ = $1;
   $$ = $1;
+}
+        | TYPEPACK_IDENTIFIER
+{
+  $$ = $1;
 }
 }
         | KW_OVERRIDE
         | KW_OVERRIDE
 {
 {

+ 26 - 3
dtool/src/cppparser/cppClassTemplateParameter.cxx

@@ -21,7 +21,8 @@ CPPClassTemplateParameter::
 CPPClassTemplateParameter(CPPIdentifier *ident, CPPType *default_type) :
 CPPClassTemplateParameter(CPPIdentifier *ident, CPPType *default_type) :
   CPPType(CPPFile()),
   CPPType(CPPFile()),
   _ident(ident),
   _ident(ident),
-  _default_type(default_type)
+  _default_type(default_type),
+  _packed(false)
 {
 {
 }
 }
 
 
@@ -41,8 +42,14 @@ is_fully_specified() const {
 void CPPClassTemplateParameter::
 void CPPClassTemplateParameter::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
   if (complete) {
   if (complete) {
-    out << "class ";
-    _ident->output(out, scope);
+    out << "class";
+    if (_packed) {
+      out << "...";
+    }
+    if (_ident != NULL) {
+      out << " ";
+      _ident->output(out, scope);
+    }
     if (_default_type) {
     if (_default_type) {
       out << " = ";
       out << " = ";
       _default_type->output(out, indent_level, scope, false);
       _default_type->output(out, indent_level, scope, false);
@@ -82,6 +89,14 @@ is_equal(const CPPDeclaration *other) const {
     return false;
     return false;
   }
   }
 
 
+  if (_packed != ot->_packed) {
+    return false;
+  }
+
+  if (_ident == NULL || ot->_ident == NULL) {
+    return _ident == ot->_ident;
+  }
+
   return *_ident == *ot->_ident;
   return *_ident == *ot->_ident;
 }
 }
 
 
@@ -99,5 +114,13 @@ is_less(const CPPDeclaration *other) const {
     return _default_type < ot->_default_type;
     return _default_type < ot->_default_type;
   }
   }
 
 
+  if (_packed != ot->_packed) {
+    return _packed < ot->_packed;
+  }
+
+  if (_ident == NULL || ot->_ident == NULL) {
+    return _ident < ot->_ident;
+  }
+
   return *_ident < *ot->_ident;
   return *_ident < *ot->_ident;
 }
 }

+ 1 - 0
dtool/src/cppparser/cppClassTemplateParameter.h

@@ -37,6 +37,7 @@ public:
 
 
   CPPIdentifier *_ident;
   CPPIdentifier *_ident;
   CPPType *_default_type;
   CPPType *_default_type;
+  bool _packed;
 
 
 protected:
 protected:
   virtual bool is_equal(const CPPDeclaration *other) const;
   virtual bool is_equal(const CPPDeclaration *other) const;

+ 42 - 1
dtool/src/cppparser/cppConstType.cxx

@@ -86,6 +86,22 @@ is_tbd() const {
   return _wrapped_around->is_tbd();
   return _wrapped_around->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPConstType::
+is_fundamental() const {
+  return _wrapped_around->is_fundamental();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPConstType::
+is_standard_layout() const {
+  return _wrapped_around->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -94,12 +110,20 @@ is_trivial() const {
   return _wrapped_around->is_trivial();
   return _wrapped_around->is_trivial();
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPConstType::
+is_constructible(const CPPType *given_type) const {
+  return _wrapped_around->is_constructible(given_type);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
 bool CPPConstType::
 bool CPPConstType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return false;
+  return _wrapped_around->is_default_constructible();
 }
 }
 
 
 /**
 /**
@@ -110,6 +134,23 @@ is_copy_constructible() const {
   return _wrapped_around->is_copy_constructible();
   return _wrapped_around->is_copy_constructible();
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPConstType::
+is_destructible() const {
+  return _wrapped_around->is_destructible();
+}
+
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPConstType::
+is_convertible_to(const CPPType *other) const {
+  return _wrapped_around->is_convertible_to(other);
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

+ 5 - 0
dtool/src/cppparser/cppConstType.h

@@ -36,9 +36,14 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 8 - 2
dtool/src/cppparser/cppDeclaration.cxx

@@ -41,8 +41,13 @@ CPPDeclaration(const CPPDeclaration &copy) :
 /**
 /**
  *
  *
  */
  */
-CPPDeclaration::
-~CPPDeclaration() {
+CPPDeclaration &CPPDeclaration::
+operator = (const CPPDeclaration &copy) {
+  _vis = copy._vis;
+  _template_scope = copy._template_scope;
+  _file = copy._file;
+  _leading_comment = copy._leading_comment;
+  return *this;
 }
 }
 
 
 /**
 /**
@@ -124,6 +129,7 @@ CPPDeclaration *CPPDeclaration::
 substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
 substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
   SubstDecl::const_iterator si = subst.find(this);
   SubstDecl::const_iterator si = subst.find(this);
   if (si != subst.end()) {
   if (si != subst.end()) {
+    assert((*si).second != NULL);
     return (*si).second;
     return (*si).second;
   }
   }
   return this;
   return this;

+ 70 - 1
dtool/src/cppparser/cppDeclaration.h

@@ -89,7 +89,9 @@ public:
 
 
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPFile &file);
   CPPDeclaration(const CPPDeclaration &copy);
   CPPDeclaration(const CPPDeclaration &copy);
-  virtual ~CPPDeclaration();
+  virtual ~CPPDeclaration() {};
+
+  CPPDeclaration &operator = (const CPPDeclaration &copy);
 
 
   bool operator == (const CPPDeclaration &other) const;
   bool operator == (const CPPDeclaration &other) const;
   bool operator != (const CPPDeclaration &other) const;
   bool operator != (const CPPDeclaration &other) const;
@@ -139,6 +141,73 @@ public:
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeSeq *as_make_seq();
   virtual CPPMakeSeq *as_make_seq();
 
 
+  inline const CPPInstance *as_instance() const {
+    return ((CPPDeclaration *)this)->as_instance();
+  }
+  inline const CPPClassTemplateParameter *as_class_template_parameter() const {
+    return ((CPPDeclaration *)this)->as_class_template_parameter();
+  }
+  inline const CPPTypedefType *as_typedef_type() const {
+    return ((CPPDeclaration *)this)->as_typedef_type();
+  }
+  inline const CPPTypeDeclaration *as_type_declaration() const {
+    return ((CPPDeclaration *)this)->as_type_declaration();
+  }
+  inline const CPPExpression *as_expression() const {
+    return ((CPPDeclaration *)this)->as_expression();
+  }
+  inline const CPPType *as_type() const {
+    return ((CPPDeclaration *)this)->as_type();
+  }
+  inline const CPPNamespace *as_namespace() const {
+    return ((CPPDeclaration *)this)->as_namespace();
+  }
+  inline const CPPUsing *as_using() const {
+    return ((CPPDeclaration *)this)->as_using();
+  }
+  inline const CPPSimpleType *as_simple_type() const {
+    return ((CPPDeclaration *)this)->as_simple_type();
+  }
+  inline const CPPPointerType *as_pointer_type() const {
+    return ((CPPDeclaration *)this)->as_pointer_type();
+  }
+  inline const CPPReferenceType *as_reference_type() const {
+    return ((CPPDeclaration *)this)->as_reference_type();
+  }
+  inline const CPPArrayType *as_array_type() const {
+    return ((CPPDeclaration *)this)->as_array_type();
+  }
+  inline const CPPConstType *as_const_type() const {
+    return ((CPPDeclaration *)this)->as_const_type();
+  }
+  inline const CPPFunctionType *as_function_type() const {
+    return ((CPPDeclaration *)this)->as_function_type();
+  }
+  inline const CPPFunctionGroup *as_function_group() const {
+    return ((CPPDeclaration *)this)->as_function_group();
+  }
+  inline const CPPExtensionType *as_extension_type() const {
+    return ((CPPDeclaration *)this)->as_extension_type();
+  }
+  inline const CPPStructType *as_struct_type() const {
+    return ((CPPDeclaration *)this)->as_struct_type();
+  }
+  inline const CPPEnumType *as_enum_type() const {
+    return ((CPPDeclaration *)this)->as_enum_type();
+  }
+  inline const CPPTBDType *as_tbd_type() const {
+    return ((CPPDeclaration *)this)->as_tbd_type();
+  }
+  inline const CPPTypeProxy *as_type_proxy() const {
+    return ((CPPDeclaration *)this)->as_type_proxy();
+  }
+  inline const CPPMakeProperty *as_make_property() const {
+    return ((CPPDeclaration *)this)->as_make_property();
+  }
+  inline const CPPMakeSeq *as_make_seq() const {
+    return ((CPPDeclaration *)this)->as_make_seq();
+  }
+
   CPPVisibility _vis;
   CPPVisibility _vis;
   CPPTemplateScope *_template_scope;
   CPPTemplateScope *_template_scope;
   CPPFile _file;
   CPPFile _file;

+ 212 - 7
dtool/src/cppparser/cppExpression.cxx

@@ -24,6 +24,7 @@
 #include "cppInstance.h"
 #include "cppInstance.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
+#include "cppStructType.h"
 #include "cppBison.h"
 #include "cppBison.h"
 #include "pdtoa.h"
 #include "pdtoa.h"
 
 
@@ -389,6 +390,19 @@ typeid_op(CPPExpression *op1, CPPType *std_type_info) {
   return expr;
   return expr;
 }
 }
 
 
+/**
+ * Creates an expression that returns a particular type trait.
+ */
+CPPExpression CPPExpression::
+type_trait(int trait, CPPType *type, CPPType *arg) {
+  CPPExpression expr(0);
+  expr._type = T_type_trait;
+  expr._u._type_trait._trait = trait;
+  expr._u._type_trait._type = type;
+  expr._u._type_trait._arg = arg;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -401,6 +415,17 @@ sizeof_func(CPPType *type) {
   return expr;
   return expr;
 }
 }
 
 
+/**
+ *
+ */
+CPPExpression CPPExpression::
+sizeof_ellipsis_func(CPPIdentifier *ident) {
+  CPPExpression expr(0);
+  expr._type = T_sizeof_ellipsis;
+  expr._u._ident = ident;
+  return expr;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -492,13 +517,6 @@ get_delete() {
   return expr;
   return expr;
 }
 }
 
 
-/**
- *
- */
-CPPExpression::
-~CPPExpression() {
-}
-
 /**
 /**
  *
  *
  */
  */
@@ -579,6 +597,7 @@ evaluate() const {
   case T_new:
   case T_new:
   case T_default_new:
   case T_default_new:
   case T_sizeof:
   case T_sizeof:
+  case T_sizeof_ellipsis:
     return Result();
     return Result();
 
 
   case T_alignof:
   case T_alignof:
@@ -801,6 +820,95 @@ evaluate() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return Result();
     return Result();
 
 
+  case T_type_trait:
+    switch (_u._type_trait._trait) {
+    case KW_HAS_VIRTUAL_DESTRUCTOR:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->has_virtual_destructor());
+      }
+
+    case KW_IS_ABSTRACT:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_abstract());
+      }
+
+    case KW_IS_BASE_OF:
+      {
+        CPPStructType *struct_type1 = _u._type_trait._type->as_struct_type();
+        CPPStructType *struct_type2 = _u._type_trait._arg->as_struct_type();
+        return Result(struct_type1 != NULL && struct_type2 != NULL && struct_type1->is_base_of(struct_type2));
+      }
+
+    case KW_IS_CLASS:
+      {
+        CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type();
+        return Result(ext_type != NULL && (
+          ext_type->_type == CPPExtensionType::T_class ||
+          ext_type->_type == CPPExtensionType::T_struct));
+      }
+
+    case KW_IS_CONSTRUCTIBLE:
+      if (_u._type_trait._arg == NULL) {
+        return Result(_u._type_trait._type->is_default_constructible());
+      } else {
+        return Result(_u._type_trait._type->is_constructible(_u._type_trait._arg));
+      }
+
+    case KW_IS_CONVERTIBLE_TO:
+      assert(_u._type_trait._arg != NULL);
+      return Result(_u._type_trait._type->is_convertible_to(_u._type_trait._arg));
+
+    case KW_IS_DESTRUCTIBLE:
+      return Result(_u._type_trait._type->is_destructible());
+
+    case KW_IS_EMPTY:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_empty());
+      }
+
+    case KW_IS_ENUM:
+      return Result(_u._type_trait._type->is_enum());
+
+    case KW_IS_FINAL:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_final());
+      }
+
+    case KW_IS_FUNDAMENTAL:
+      return Result(_u._type_trait._type->is_fundamental());
+
+    case KW_IS_POD:
+      return Result(_u._type_trait._type->is_trivial() &&
+                    _u._type_trait._type->is_standard_layout());
+
+    case KW_IS_POLYMORPHIC:
+      {
+        CPPStructType *struct_type = _u._type_trait._type->as_struct_type();
+        return Result(struct_type != NULL && struct_type->is_polymorphic());
+      }
+
+    case KW_IS_STANDARD_LAYOUT:
+      return Result(_u._type_trait._type->is_standard_layout());
+
+    case KW_IS_TRIVIAL:
+      return Result(_u._type_trait._type->is_trivial());
+
+    case KW_IS_UNION:
+      {
+        CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type();
+        return Result(ext_type != NULL &&
+          ext_type->_type == CPPExtensionType::T_union);
+      }
+
+    default:
+      cerr << "**unexpected type trait**\n";
+      abort();
+    }
+
   default:
   default:
     cerr << "**invalid operand**\n";
     cerr << "**invalid operand**\n";
     abort();
     abort();
@@ -916,6 +1024,7 @@ determine_type() const {
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
 
 
   case T_sizeof:
   case T_sizeof:
+  case T_sizeof_ellipsis:
   case T_alignof:
   case T_alignof:
     // Note: this should actually be size_t, but that is defined as a typedef
     // Note: this should actually be size_t, but that is defined as a typedef
     // in parser-inc.  We could try to resolve it, but that's hacky.  Eh, it's
     // in parser-inc.  We could try to resolve it, but that's hacky.  Eh, it's
@@ -1057,6 +1166,9 @@ determine_type() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._std_type_info;
     return _u._typeid._std_type_info;
 
 
+  case T_type_trait:
+    return bool_type;
+
   default:
   default:
     cerr << "**invalid operand**\n";
     cerr << "**invalid operand**\n";
     abort();
     abort();
@@ -1113,6 +1225,9 @@ is_fully_specified() const {
   case T_alignof:
   case T_alignof:
     return _u._typecast._to->is_fully_specified();
     return _u._typecast._to->is_fully_specified();
 
 
+  case T_sizeof_ellipsis:
+    return _u._ident->is_fully_specified();
+
   case T_trinary_operation:
   case T_trinary_operation:
     if (!_u._op._op3->is_fully_specified()) {
     if (!_u._op._op3->is_fully_specified()) {
       return false;
       return false;
@@ -1141,6 +1256,9 @@ is_fully_specified() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr->is_fully_specified();
     return _u._typeid._expr->is_fully_specified();
 
 
+  case T_type_trait:
+    return _u._type_trait._type->is_fully_specified();
+
   default:
   default:
     return true;
     return true;
   }
   }
@@ -1276,6 +1394,13 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr);
     any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr);
     break;
     break;
 
 
+  case T_type_trait:
+    rep->_u._type_trait._type =
+      _u._type_trait._type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+    any_changed = any_changed || (rep->_u._type_trait._type != _u._type_trait._type);
+    break;
+
   default:
   default:
     break;
     break;
   }
   }
@@ -1350,6 +1475,9 @@ is_tbd() const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr->is_tbd();
     return _u._typeid._expr->is_tbd();
 
 
+  case T_type_trait:
+    return _u._type_trait._type->is_tbd();
+
   default:
   default:
     return false;
     return false;
   }
   }
@@ -1541,6 +1669,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << ")";
     out << ")";
     break;
     break;
 
 
+  case T_sizeof_ellipsis:
+    out << "sizeof...(";
+    _u._ident->output(out, scope);
+    out << ")";
+    break;
+
   case T_alignof:
   case T_alignof:
     out << "alignof(";
     out << "alignof(";
     _u._typecast._to->output(out, indent_level, scope, false);
     _u._typecast._to->output(out, indent_level, scope, false);
@@ -1753,6 +1887,65 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << "delete";
     out << "delete";
     break;
     break;
 
 
+  case T_type_trait:
+    switch (_u._type_trait._trait) {
+    case KW_HAS_VIRTUAL_DESTRUCTOR:
+      out << "__has_virtual_destructor";
+      break;
+    case KW_IS_ABSTRACT:
+      out << "__is_abstract";
+      break;
+    case KW_IS_BASE_OF:
+      out << "__is_base_of";
+      break;
+    case KW_IS_CLASS:
+      out << "__is_class";
+      break;
+    case KW_IS_CONSTRUCTIBLE:
+      out << "__is_constructible";
+      break;
+    case KW_IS_CONVERTIBLE_TO:
+      out << "__is_convertible_to";
+      break;
+    case KW_IS_DESTRUCTIBLE:
+      out << "__is_destructible";
+      break;
+    case KW_IS_EMPTY:
+      out << "__is_empty";
+      break;
+    case KW_IS_ENUM:
+      out << "__is_enum";
+      break;
+    case KW_IS_FINAL:
+      out << "__is_final";
+      break;
+    case KW_IS_FUNDAMENTAL:
+      out << "__is_fundamental";
+      break;
+    case KW_IS_POD:
+      out << "__is_pod";
+      break;
+    case KW_IS_POLYMORPHIC:
+      out << "__is_polymorphic";
+      break;
+    case KW_IS_STANDARD_LAYOUT:
+      out << "__is_standard_layout";
+      break;
+    case KW_IS_TRIVIAL:
+      out << "__is_trivial";
+      break;
+    case KW_IS_UNION:
+      out << "__is_union";
+      break;
+    default:
+      out << (evaluate().as_boolean() ? "true" : "false");
+      return;
+    }
+    out << '(';
+    _u._type_trait._type->output(out, indent_level, scope, false);
+    out << ')';
+    break;
+
   default:
   default:
     out << "(** invalid operand type " << (int)_type << " **)";
     out << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -1864,6 +2057,7 @@ is_equal(const CPPDeclaration *other) const {
     return _u._fgroup == ot->_u._fgroup;
     return _u._fgroup == ot->_u._fgroup;
 
 
   case T_unknown_ident:
   case T_unknown_ident:
+  case T_sizeof_ellipsis:
     return *_u._ident == *ot->_u._ident;
     return *_u._ident == *ot->_u._ident;
 
 
   case T_typecast:
   case T_typecast:
@@ -1907,6 +2101,10 @@ is_equal(const CPPDeclaration *other) const {
   case T_typeid_expr:
   case T_typeid_expr:
     return _u._typeid._expr == ot->_u._typeid._expr;
     return _u._typeid._expr == ot->_u._typeid._expr;
 
 
+  case T_type_trait:
+    return _u._type_trait._trait == ot->_u._type_trait._trait &&
+           _u._type_trait._type == ot->_u._type_trait._type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }
@@ -1954,6 +2152,7 @@ is_less(const CPPDeclaration *other) const {
     return *_u._fgroup < *ot->_u._fgroup;
     return *_u._fgroup < *ot->_u._fgroup;
 
 
   case T_unknown_ident:
   case T_unknown_ident:
+  case T_sizeof_ellipsis:
     return *_u._ident < *ot->_u._ident;
     return *_u._ident < *ot->_u._ident;
 
 
   case T_typecast:
   case T_typecast:
@@ -2007,6 +2206,12 @@ is_less(const CPPDeclaration *other) const {
   case T_typeid_expr:
   case T_typeid_expr:
     return *_u._typeid._expr < *ot->_u._typeid._expr;
     return *_u._typeid._expr < *ot->_u._typeid._expr;
 
 
+  case T_type_trait:
+    if (_u._type_trait._trait != ot->_u._type_trait._trait) {
+      return _u._type_trait._trait < ot->_u._type_trait._trait;
+    }
+    return *_u._type_trait._type < *ot->_u._type_trait._type;
+
   default:
   default:
     cerr << "(** invalid operand type " << (int)_type << " **)";
     cerr << "(** invalid operand type " << (int)_type << " **)";
   }
   }

+ 9 - 2
dtool/src/cppparser/cppExpression.h

@@ -51,6 +51,7 @@ public:
     T_new,
     T_new,
     T_default_new,
     T_default_new,
     T_sizeof,
     T_sizeof,
+    T_sizeof_ellipsis,
     T_alignof,
     T_alignof,
     T_unary_operation,
     T_unary_operation,
     T_binary_operation,
     T_binary_operation,
@@ -59,6 +60,7 @@ public:
     T_raw_literal,
     T_raw_literal,
     T_typeid_type,
     T_typeid_type,
     T_typeid_expr,
     T_typeid_expr,
+    T_type_trait,
 
 
     // These are used when parsing =default and =delete methods.
     // These are used when parsing =default and =delete methods.
     T_default,
     T_default,
@@ -81,7 +83,9 @@ public:
   static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
   static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
   static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
+  static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = NULL);
   static CPPExpression sizeof_func(CPPType *type);
   static CPPExpression sizeof_func(CPPType *type);
+  static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression alignof_func(CPPType *type);
 
 
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
   static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
@@ -93,8 +97,6 @@ public:
   static const CPPExpression &get_default();
   static const CPPExpression &get_default();
   static const CPPExpression &get_delete();
   static const CPPExpression &get_delete();
 
 
-  ~CPPExpression();
-
   enum ResultType {
   enum ResultType {
     RT_integer,
     RT_integer,
     RT_real,
     RT_real,
@@ -170,6 +172,11 @@ public:
       CPPInstance *_operator;
       CPPInstance *_operator;
       CPPExpression *_value;
       CPPExpression *_value;
     } _literal;
     } _literal;
+    struct {
+      int _trait;
+      CPPType *_type;
+      CPPType *_arg;
+    } _type_trait;
   } _u;
   } _u;
 
 
 protected:
 protected:

+ 23 - 3
dtool/src/cppparser/cppExtensionType.cxx

@@ -87,12 +87,32 @@ is_tbd() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPExtensionType::
+is_standard_layout() const {
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_trivial() const {
 is_trivial() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
+}
+
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPExtensionType::
+is_constructible(const CPPType *given_type) const {
+  if (_type == T_enum || _type == T_enum_class || _type == T_enum_struct) {
+    const CPPExtensionType *other = ((CPPType *)given_type)->remove_reference()->remove_const()->as_extension_type();
+    return other != NULL && is_equal(other);
+  }
+  return false;
 }
 }
 
 
 /**
 /**
@@ -100,7 +120,7 @@ is_trivial() const {
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_default_constructible() const {
 is_default_constructible() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
 }
 }
 
 
 /**
 /**
@@ -108,7 +128,7 @@ is_default_constructible() const {
  */
  */
 bool CPPExtensionType::
 bool CPPExtensionType::
 is_copy_constructible() const {
 is_copy_constructible() const {
-  return (_type == T_enum);
+  return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct);
 }
 }
 
 
 /**
 /**

+ 2 - 0
dtool/src/cppparser/cppExtensionType.h

@@ -47,7 +47,9 @@ public:
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
 
 

+ 1 - 1
dtool/src/cppparser/cppFile.h

@@ -55,7 +55,7 @@ public:
 
 
   Filename _filename;
   Filename _filename;
   Filename _filename_as_referenced;
   Filename _filename_as_referenced;
-  Source _source;
+  mutable Source _source;
   mutable bool _pragma_once;
   mutable bool _pragma_once;
 };
 };
 
 

+ 14 - 6
dtool/src/cppparser/cppFunctionType.cxx

@@ -89,9 +89,11 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   }
   }
 
 
   CPPFunctionType *rep = new CPPFunctionType(*this);
   CPPFunctionType *rep = new CPPFunctionType(*this);
-  rep->_return_type =
-    _return_type->substitute_decl(subst, current_scope, global_scope)
-    ->as_type();
+  if (_return_type != NULL) {
+    rep->_return_type =
+      _return_type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+  }
 
 
   rep->_parameters =
   rep->_parameters =
     _parameters->substitute_decl(subst, current_scope, global_scope);
     _parameters->substitute_decl(subst, current_scope, global_scope);
@@ -265,6 +267,9 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
   if (_flags & F_const_method) {
   if (_flags & F_const_method) {
     out << " const";
     out << " const";
   }
   }
+  if (_flags & F_volatile_method) {
+    out << " volatile";
+  }
   if (_flags & F_noexcept) {
   if (_flags & F_noexcept) {
     out << " noexcept";
     out << " noexcept";
   }
   }
@@ -321,14 +326,17 @@ as_function_type() {
  * This is similar to is_equal(), except it is more forgiving: it considers
  * This is similar to is_equal(), except it is more forgiving: it considers
  * the functions to be equivalent only if the return type and the types of all
  * the functions to be equivalent only if the return type and the types of all
  * parameters match.
  * parameters match.
+ *
+ * Note that this isn't symmetric to account for covariant return types.
  */
  */
 bool CPPFunctionType::
 bool CPPFunctionType::
-is_equivalent_function(const CPPFunctionType &other) const {
-  if (!_return_type->is_equivalent(*other._return_type)) {
+match_virtual_override(const CPPFunctionType &other) const {
+  if (!_return_type->is_equivalent(*other._return_type) &&
+      !_return_type->is_convertible_to(other._return_type)) {
     return false;
     return false;
   }
   }
 
 
-  if (_flags != other._flags) {
+  if (((_flags ^ other._flags) & ~(F_override | F_final)) != 0) {
     return false;
     return false;
   }
   }
 
 

+ 4 - 1
dtool/src/cppparser/cppFunctionType.h

@@ -40,6 +40,9 @@ public:
     F_trailing_return_type = 0x800,
     F_trailing_return_type = 0x800,
     F_final             = 0x1000,
     F_final             = 0x1000,
     F_override          = 0x2000,
     F_override          = 0x2000,
+    F_volatile_method   = 0x4000,
+    F_lvalue_method     = 0x8000,
+    F_rvalue_method     = 0x10000,
   };
   };
 
 
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
   CPPFunctionType(CPPType *return_type, CPPParameterList *parameters,
@@ -81,7 +84,7 @@ public:
 
 
   virtual CPPFunctionType *as_function_type();
   virtual CPPFunctionType *as_function_type();
 
 
-  bool is_equivalent_function(const CPPFunctionType &other) const;
+  bool match_virtual_override(const CPPFunctionType &other) const;
 
 
   CPPIdentifier *_class_owner;
   CPPIdentifier *_class_owner;
 
 

+ 8 - 5
dtool/src/cppparser/cppInstance.cxx

@@ -82,6 +82,10 @@ CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
     // anyway.
     // anyway.
   }
   }
 
 
+  if (ii->_packed) {
+    _storage_class |= SC_parameter_pack;
+  }
+
   delete ii;
   delete ii;
 }
 }
 
 
@@ -353,11 +357,7 @@ check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) {
           CPPReferenceType *ref_type = param_type->as_reference_type();
           CPPReferenceType *ref_type = param_type->as_reference_type();
 
 
           if (ref_type != NULL) {
           if (ref_type != NULL) {
-            param_type = ref_type->_pointing_at;
-
-            if (param_type->get_subtype() == CPPDeclaration::ST_const) {
-              param_type = param_type->as_const_type()->_wrapped_around;
-            }
+            param_type = ref_type->_pointing_at->remove_cv();
 
 
             if (class_name == param_type->get_simple_name()) {
             if (class_name == param_type->get_simple_name()) {
               if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
               if (ref_type->_value_category == CPPReferenceType::VC_rvalue) {
@@ -563,6 +563,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
   if (_ident != NULL) {
   if (_ident != NULL) {
     name = _ident->get_local_name(scope);
     name = _ident->get_local_name(scope);
   }
   }
+  if (_storage_class & SC_parameter_pack) {
+    name = "..." + name;
+  }
 
 
   if (_type->as_function_type()) {
   if (_type->as_function_type()) {
     _type->as_function_type()->
     _type->as_function_type()->

+ 3 - 0
dtool/src/cppparser/cppInstance.h

@@ -68,6 +68,9 @@ public:
     // This isn't really a storage class.  It's only used temporarily by the
     // This isn't really a storage class.  It's only used temporarily by the
     // parser, to make parsing specifier sequences a bit easier.
     // parser, to make parsing specifier sequences a bit easier.
     SC_const        = 0x20000,
     SC_const        = 0x20000,
+
+    // Used to indicate that this is a parameter pack.
+    SC_parameter_pack = 0x40000,
   };
   };
 
 
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);
   CPPInstance(CPPType *type, const string &name, int storage_class = 0);

+ 7 - 7
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -26,12 +26,11 @@
  */
  */
 CPPInstanceIdentifier::Modifier::
 CPPInstanceIdentifier::Modifier::
 Modifier(CPPInstanceIdentifierType type) :
 Modifier(CPPInstanceIdentifierType type) :
-  _type(type)
-{
-  _func_params = NULL;
-  _func_flags = 0;
-  _scoping = NULL;
-  _expr = NULL;
+  _type(type),
+  _func_params(NULL),
+  _func_flags(0),
+  _scoping(NULL),
+  _expr(NULL) {
 }
 }
 
 
 /**
 /**
@@ -83,7 +82,8 @@ initializer_type(CPPParameterList *params) {
 CPPInstanceIdentifier::
 CPPInstanceIdentifier::
 CPPInstanceIdentifier(CPPIdentifier *ident) :
 CPPInstanceIdentifier(CPPIdentifier *ident) :
   _ident(ident),
   _ident(ident),
-  _bit_width(-1) {
+  _bit_width(-1),
+  _packed(false) {
 }
 }
 
 
 /**
 /**

+ 4 - 0
dtool/src/cppparser/cppInstanceIdentifier.h

@@ -88,8 +88,12 @@ public:
   typedef vector<Modifier> Modifiers;
   typedef vector<Modifier> Modifiers;
   Modifiers _modifiers;
   Modifiers _modifiers;
 
 
+  // If not -1, indicates a bitfield
   int _bit_width;
   int _bit_width;
 
 
+  // Indicates a parameter pack
+  bool _packed;
+
 private:
 private:
   CPPType *
   CPPType *
   r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi);
   r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi);

+ 14 - 1
dtool/src/cppparser/cppParser.cxx

@@ -45,7 +45,20 @@ is_fully_specified() const {
  */
  */
 bool CPPParser::
 bool CPPParser::
 parse_file(const Filename &filename) {
 parse_file(const Filename &filename) {
-  if (!init_cpp(CPPFile(filename, filename, CPPFile::S_local))) {
+  Filename canonical(filename);
+  canonical.make_canonical();
+
+  CPPFile file(canonical, filename, CPPFile::S_local);
+
+  // Don't read it if we included it before and it had #pragma once.
+  ParsedFiles::iterator it = _parsed_files.find(file);
+  if (it != _parsed_files.end() && it->_pragma_once) {
+    // But mark it as local.
+    it->_source = CPPFile::S_local;
+    return true;
+  }
+
+  if (!init_cpp(file)) {
     cerr << "Unable to read " << filename << "\n";
     cerr << "Unable to read " << filename << "\n";
     return false;
     return false;
   }
   }

+ 65 - 0
dtool/src/cppparser/cppPointerType.cxx

@@ -14,6 +14,9 @@
 #include "cppPointerType.h"
 #include "cppPointerType.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
+#include "cppArrayType.h"
+#include "cppStructType.h"
+#include "cppSimpleType.h"
 
 
 /**
 /**
  *
  *
@@ -88,6 +91,14 @@ is_tbd() const {
   return _pointing_at->is_tbd();
   return _pointing_at->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPPointerType::
+is_standard_layout() const {
+  return true;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -96,6 +107,60 @@ is_trivial() const {
   return true;
   return true;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPPointerType::
+is_constructible(const CPPType *given_type) const {
+  given_type = ((CPPType *)given_type)->remove_reference()->remove_cv();
+
+  // Can convert from compatible pointer or array type.
+  CPPType *other_target;
+  switch (given_type->get_subtype()) {
+  case ST_array:
+    other_target = given_type->as_array_type()->_element_type;
+    break;
+
+  case ST_pointer:
+    other_target = given_type->as_pointer_type()->_pointing_at;
+    break;
+
+  case ST_simple:
+    // Can initialize from nullptr.
+    return given_type->as_simple_type()->_type == CPPSimpleType::T_nullptr;
+
+  default:
+    return false;
+  }
+
+  // Can't convert const to non-const pointer.
+  if (other_target->is_const() && !_pointing_at->is_const()) {
+    return false;
+  }
+
+  // Are we pointing to the same type?  That's always OK.
+  const CPPType *a = _pointing_at->remove_cv();
+  const CPPType *b = other_target->remove_cv();
+  if (a == b || *a == *b) {
+    return true;
+  }
+
+  // Can initialize void pointer with any pointer.
+  const CPPSimpleType *simple_type = a->as_simple_type();
+  if (simple_type != NULL) {
+    return simple_type->_type == CPPSimpleType::T_void;
+  }
+
+  // Can initialize from derived class pointer.
+  const CPPStructType *a_struct = a->as_struct_type();
+  const CPPStructType *b_struct = b->as_struct_type();
+  if (a_struct != NULL && b_struct != NULL) {
+    return a_struct->is_base_of(b_struct);
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */

+ 2 - 0
dtool/src/cppparser/cppPointerType.h

@@ -36,7 +36,9 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *other) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;

+ 257 - 83
dtool/src/cppparser/cppPreprocessor.cxx

@@ -18,6 +18,7 @@
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateParameterList.h"
 #include "cppTemplateParameterList.h"
+#include "cppClassTemplateParameter.h"
 #include "cppConstType.h"
 #include "cppConstType.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionGroup.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
@@ -416,7 +417,14 @@ get_next_token0() {
     int token_type = IDENTIFIER;
     int token_type = IDENTIFIER;
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
     if (decl != NULL && decl->as_type() != NULL) {
     if (decl != NULL && decl->as_type() != NULL) {
-      token_type = TYPENAME_IDENTIFIER;
+      // We need to see type pack template parameters as a different type of
+      // identifier to resolve a parser ambiguity.
+      CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
+      if (ctp && ctp->_packed) {
+        token_type = TYPEPACK_IDENTIFIER;
+      } else {
+        token_type = TYPENAME_IDENTIFIER;
+      }
     }
     }
 
 
     _last_token_loc = loc;
     _last_token_loc = loc;
@@ -801,6 +809,8 @@ expand_manifests(const string &input_expr, bool expand_undefined,
         // Here's an identifier.  Is it "defined"?
         // Here's an identifier.  Is it "defined"?
         if (ident == "defined") {
         if (ident == "defined") {
           expand_defined_function(expr, q, p);
           expand_defined_function(expr, q, p);
+        } else if (expand_undefined && ident == "__has_include") {
+          expand_has_include_function(expr, q, p, loc);
         } else {
         } else {
           // Is it a manifest?
           // Is it a manifest?
           Manifests::const_iterator mi = _manifests.find(ident);
           Manifests::const_iterator mi = _manifests.find(ident);
@@ -809,6 +819,20 @@ expand_manifests(const string &input_expr, bool expand_undefined,
             expand_manifest_inline(expr, q, p, manifest);
             expand_manifest_inline(expr, q, p, manifest);
             manifest_found = true;
             manifest_found = true;
 
 
+          } else if (ident == "__FILE__") {
+            // Special case: this is a dynamic definition.
+            string file = string("\"") + loc.file._filename_as_referenced.get_fullpath() + "\"";
+            expr = expr.substr(0, q) + file + expr.substr(p);
+            p = q + file.size();
+            manifest_found = true;
+
+          } else if (ident == "__LINE__") {
+            // So is this.
+            string line = format_string(loc.first_line);
+            expr = expr.substr(0, q) + line + expr.substr(p);
+            p = q + line.size();
+            manifest_found = true;
+
           } else if (expand_undefined && ident != "true" && ident != "false") {
           } else if (expand_undefined && ident != "true" && ident != "false") {
             // It is not found.  Expand it to 0, but only if we are currently
             // It is not found.  Expand it to 0, but only if we are currently
             // parsing an #if expression.
             // parsing an #if expression.
@@ -951,7 +975,7 @@ internal_get_next_token() {
     case ',':
     case ',':
       if (_paren_nesting <= 0) {
       if (_paren_nesting <= 0) {
         _state = S_end_nested;
         _state = S_end_nested;
-        return CPPToken::eof();
+        return CPPToken(0, loc);
       }
       }
       break;
       break;
 
 
@@ -959,7 +983,7 @@ internal_get_next_token() {
       if (_paren_nesting <= 0) {
       if (_paren_nesting <= 0) {
         _parsing_template_params = false;
         _parsing_template_params = false;
         _state = S_end_nested;
         _state = S_end_nested;
-        return CPPToken::eof();
+        return CPPToken(0, loc);
       }
       }
     }
     }
   }
   }
@@ -1453,7 +1477,6 @@ handle_define_directive(const string &args, const YYLTYPE &loc) {
       CPPManifest *other = result.first->second;
       CPPManifest *other = result.first->second;
       warning("redefinition of macro '" + manifest->_name + "'", loc);
       warning("redefinition of macro '" + manifest->_name + "'", loc);
       warning("previous definition is here", other->_loc);
       warning("previous definition is here", other->_loc);
-      delete other;
       result.first->second = manifest;
       result.first->second = manifest;
     }
     }
   }
   }
@@ -1479,14 +1502,10 @@ handle_undef_directive(const string &args, const YYLTYPE &loc) {
  */
  */
 void CPPPreprocessor::
 void CPPPreprocessor::
 handle_ifdef_directive(const string &args, const YYLTYPE &loc) {
 handle_ifdef_directive(const string &args, const YYLTYPE &loc) {
-  Manifests::const_iterator mi = _manifests.find(args);
-  if (mi != _manifests.end()) {
-    // The macro is defined.  We continue.
-    return;
+  if (!is_manifest_defined(args)) {
+    // The macro is undefined.  Skip stuff.
+    skip_false_if_block(true);
   }
   }
-
-  // The macro is undefined.  Skip stuff.
-  skip_false_if_block(true);
 }
 }
 
 
 /**
 /**
@@ -1494,17 +1513,12 @@ handle_ifdef_directive(const string &args, const YYLTYPE &loc) {
  */
  */
 void CPPPreprocessor::
 void CPPPreprocessor::
 handle_ifndef_directive(const string &args, const YYLTYPE &loc) {
 handle_ifndef_directive(const string &args, const YYLTYPE &loc) {
-  Manifests::const_iterator mi = _manifests.find(args);
-  if (mi == _manifests.end()) {
-    // The macro is undefined.  We continue.
-    return;
+  if (is_manifest_defined(args)) {
+    // The macro is defined.  Skip stuff.
+    skip_false_if_block(true);
   }
   }
-
-  // The macro is defined.  Skip stuff.
-  skip_false_if_block(true);
 }
 }
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -1586,6 +1600,8 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
         _angle_includes.insert(filename);
         _angle_includes.insert(filename);
       }
       }
     }
     }
+  } else {
+    warning("Ignoring invalid #include directive", loc);
   }
   }
 
 
   filename.set_text();
   filename.set_text();
@@ -1593,71 +1609,30 @@ handle_include_directive(const string &args, const YYLTYPE &loc) {
 
 
   // Now look for the filename.  If we didn't use angle quotes, look first in
   // Now look for the filename.  If we didn't use angle quotes, look first in
   // the current directory.
   // the current directory.
-  bool found_file = false;
   CPPFile::Source source = CPPFile::S_none;
   CPPFile::Source source = CPPFile::S_none;
 
 
-  if (okflag) {
-    found_file = false;
+  if (find_include(filename, angle_quotes, source)) {
+    _last_c = '\0';
 
 
-    // Search the current directory.
-    if (!angle_quotes && !found_file && filename.exists()) {
-      found_file = true;
+    // If it was explicitly named on the command-line, mark it S_local.
+    filename.make_canonical();
+    if (_explicit_files.count(filename)) {
       source = CPPFile::S_local;
       source = CPPFile::S_local;
     }
     }
 
 
-    // Search the same directory as the includer.
-    if (!angle_quotes && !found_file) {
-      Filename match(get_file()._filename.get_dirname(), filename);
-      if (match.exists()) {
-        filename = match;
-        found_file = true;
-        source = CPPFile::S_alternate;
-      }
-    }
+    CPPFile file(filename, filename_as_referenced, source);
 
 
-    // Now search the angle-include-path
-    if (angle_quotes && !found_file && filename.resolve_filename(_angle_include_path)) {
-      found_file = true;
-      source = CPPFile::S_system;
+    // Don't include it if we included it before and it had #pragma once.
+    ParsedFiles::const_iterator it = _parsed_files.find(file);
+    if (it != _parsed_files.end() && it->_pragma_once) {
+      return;
     }
     }
 
 
-    // Now search the quote-include-path
-    if (!angle_quotes && !found_file) {
-      for (size_t dir=0; dir<_quote_include_path.get_num_directories(); dir++) {
-        Filename match(_quote_include_path.get_directory(dir), filename);
-        if (match.exists()) {
-          filename = match;
-          found_file = true;
-          source = _quote_include_kind[dir];
-        }
-      }
-    }
-
-    if (!found_file) {
-      warning("Cannot find " + filename.get_fullpath(), loc);
-    } else {
-      _last_c = '\0';
-
-      // If it was explicitly named on the command-line, mark it S_local.
-      filename.make_absolute();
-      if (_explicit_files.count(filename)) {
-        source = CPPFile::S_local;
-      }
-
-      CPPFile file(filename, filename_as_referenced, source);
-
-      // Don't include it if we included it before and it had #pragma once.
-      ParsedFiles::const_iterator it = _parsed_files.find(file);
-      if (it != _parsed_files.end() && it->_pragma_once) {
-        return;
-      }
-
-      if (!push_file(file)) {
-        warning("Unable to read " + filename.get_fullpath(), loc);
-      }
+    if (!push_file(file)) {
+      warning("Unable to read " + filename.get_fullpath(), loc);
     }
     }
   } else {
   } else {
-    warning("Ignoring invalid #include directive", loc);
+    warning("Cannot find " + filename.get_fullpath(), loc);
   }
   }
 }
 }
 
 
@@ -1671,6 +1646,38 @@ handle_pragma_directive(const string &args, const YYLTYPE &loc) {
     assert(it != _parsed_files.end());
     assert(it != _parsed_files.end());
     it->_pragma_once = true;
     it->_pragma_once = true;
   }
   }
+
+  char macro[64];
+  if (sscanf(args.c_str(), "push_macro ( \"%63[^\"]\" )", macro) == 1) {
+    // We just mark it as pushed for now, so that the next time someone tries
+    // to override it, we save the old value.
+    Manifests::iterator mi = _manifests.find(macro);
+    if (mi != _manifests.end()) {
+      _manifest_stack[macro].push_back(mi->second);
+    } else {
+      _manifest_stack[macro].push_back(NULL);
+    }
+
+  } else if (sscanf(args.c_str(), "pop_macro ( \"%63[^\"]\" )", macro) == 1) {
+    ManifestStack &stack = _manifest_stack[macro];
+    if (stack.size() > 0) {
+      CPPManifest *manifest = stack.back();
+      stack.pop_back();
+      Manifests::iterator mi = _manifests.find(macro);
+      if (manifest == NULL) {
+        // It was undefined when it was pushed, so make it undefined again.
+        if (mi != _manifests.end()) {
+          _manifests.erase(mi);
+        }
+      } else if (mi != _manifests.end()) {
+        mi->second = manifest;
+      } else {
+        _manifests.insert(Manifests::value_type(macro, manifest));
+      }
+    } else {
+      warning("pop_macro without matching push_macro", loc);
+    }
+  }
 }
 }
 
 
 /**
 /**
@@ -1740,6 +1747,69 @@ skip_false_if_block(bool consider_elifs) {
   _save_comments = true;
   _save_comments = true;
 }
 }
 
 
+/**
+ * Returns true if the given manifest is defined.
+ */
+bool CPPPreprocessor::
+is_manifest_defined(const string &manifest_name) {
+  Manifests::const_iterator mi = _manifests.find(manifest_name);
+  if (mi != _manifests.end()) {
+    return true;
+  }
+
+  if (manifest_name == "__has_include" ||
+      manifest_name == "__FILE__" ||
+      manifest_name == "__LINE__") {
+    // Special built-in directives that are considered "defined".
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Locates the given filename.  Changes the first argument to the full path.
+ */
+bool CPPPreprocessor::
+find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source) {
+  // Now look for the filename.  If we didn't use angle quotes, look first in
+  // the current directory.
+  if (!angle_quotes && filename.exists()) {
+    source = CPPFile::S_local;
+    return true;
+  }
+
+  // Search the same directory as the includer.
+  if (!angle_quotes) {
+    Filename match(get_file()._filename.get_dirname(), filename);
+    if (match.exists()) {
+      filename = match;
+      source = CPPFile::S_alternate;
+      return true;
+    }
+  }
+
+  // Now search the angle-include-path
+  if (angle_quotes && filename.resolve_filename(_angle_include_path)) {
+    source = CPPFile::S_system;
+    return true;
+  }
+
+  // Now search the quote-include-path
+  if (!angle_quotes) {
+    for (size_t dir = 0; dir < _quote_include_path.get_num_directories(); ++dir) {
+      Filename match(_quote_include_path.get_directory(dir), filename);
+      if (match.exists()) {
+        filename = match;
+        source = _quote_include_kind[dir];
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -1846,6 +1916,14 @@ get_identifier(int c) {
   if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) {
   if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) {
     return expand_manifest((*mi).second);
     return expand_manifest((*mi).second);
   }
   }
+  if (name == "__FILE__") {
+    return get_literal(SIMPLE_STRING, loc, loc.file._filename_as_referenced);
+  }
+  if (name == "__LINE__") {
+    YYSTYPE result;
+    result.u.integer = loc.first_line;
+    return CPPToken(INTEGER, loc, "", result);
+  }
 
 
   // Check for keywords.
   // Check for keywords.
   int kw = check_keyword(name);
   int kw = check_keyword(name);
@@ -2188,9 +2266,7 @@ expand_defined_function(string &expr, size_t q, size_t &p) {
   vector_string args;
   vector_string args;
   extract_manifest_args_inline("defined", 1, -1, args, expr, p);
   extract_manifest_args_inline("defined", 1, -1, args, expr, p);
   if (args.size() >= 1) {
   if (args.size() >= 1) {
-    const string &manifest_name = args[0];
-    Manifests::const_iterator mi = _manifests.find(manifest_name);
-    if (mi != _manifests.end()) {
+    if (is_manifest_defined(args[0])) {
       // The macro is defined; the result is "1".
       // The macro is defined; the result is "1".
       result = "1";
       result = "1";
     } else {
     } else {
@@ -2203,6 +2279,70 @@ expand_defined_function(string &expr, size_t q, size_t &p) {
   p = q + result.size();
   p = q + result.size();
 }
 }
 
 
+/**
+ * Expands the __has_include(manifest) function to either 1 or 0, depending on
+ * whether the include file exists.
+ */
+void CPPPreprocessor::
+expand_has_include_function(string &expr, size_t q, size_t &p, YYLTYPE loc) {
+  bool found_file = false;
+
+  // Skip whitespace till paren.
+  while (p < expr.size() && isspace(expr[p])) {
+    p++;
+  }
+  size_t args_begin = p + 1;
+
+  vector_string args;
+  extract_manifest_args_inline("__has_include", 1, -1, args, expr, p);
+
+  if (!args.empty() && args[0].size() >= 2) {
+    Filename filename;
+    bool angle_quotes = false;
+
+    string inc = args[0];
+
+    // Just to play things safe, since our manifest-expansion logic might not
+    // filter out quotes and angle brackets properly, we'll only expand
+    // manifests if we don't begin with a quote or bracket.
+    if (!inc.empty() && (inc[0] != '"' && inc[0] != '<')) {
+      inc = expand_manifests(inc, false, loc);
+    }
+
+    if (inc[0] == '"' && inc[inc.size() - 1] == '"') {
+      filename = inc.substr(1, inc.size() - 2);
+    } else if (inc[0] == '<' && inc[inc.size() - 1] == '>') {
+      filename = inc.substr(1, inc.size() - 2);
+      if (!_noangles) {
+        // If _noangles is true, we don't make a distinction between angle
+        // brackets and quote marks--all #inc statements are treated the
+        // same, as if they used quote marks.
+        angle_quotes = true;
+      }
+    } else {
+      loc.last_column += loc.first_column + p - 2;
+      loc.first_column += args_begin;
+      warning("invalid argument for __has_include() directive", loc);
+      expr = expr.substr(0, q) + "0" + expr.substr(p);
+      p = q + 1;
+      return;
+    }
+
+    filename.set_text();
+
+    CPPFile::Source source = CPPFile::S_none;
+    found_file = find_include(filename, angle_quotes, source);
+  } else {
+    loc.last_column += loc.first_column + p - 2;
+    loc.first_column += args_begin;
+    warning("invalid argument for __has_include() directive", loc);
+  }
+
+  string result = found_file ? "1" : "0";
+  expr = expr.substr(0, q) + result + expr.substr(p);
+  p = q + result.size();
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -2451,11 +2591,27 @@ check_keyword(const string &name) {
   if (name == "friend") return KW_FRIEND;
   if (name == "friend") return KW_FRIEND;
   if (name == "for") return KW_FOR;
   if (name == "for") return KW_FOR;
   if (name == "goto") return KW_GOTO;
   if (name == "goto") return KW_GOTO;
+  if (name == "__has_virtual_destructor") return KW_HAS_VIRTUAL_DESTRUCTOR;
   if (name == "if") return KW_IF;
   if (name == "if") return KW_IF;
   if (name == "inline") return KW_INLINE;
   if (name == "inline") return KW_INLINE;
   if (name == "__inline") return KW_INLINE;
   if (name == "__inline") return KW_INLINE;
   if (name == "__inline__") return KW_INLINE;
   if (name == "__inline__") return KW_INLINE;
   if (name == "int") return KW_INT;
   if (name == "int") return KW_INT;
+  if (name == "__is_abstract") return KW_IS_ABSTRACT;
+  if (name == "__is_base_of") return KW_IS_BASE_OF;
+  if (name == "__is_class") return KW_IS_CLASS;
+  if (name == "__is_constructible") return KW_IS_CONSTRUCTIBLE;
+  if (name == "__is_convertible_to") return KW_IS_CONVERTIBLE_TO;
+  if (name == "__is_destructible") return KW_IS_DESTRUCTIBLE;
+  if (name == "__is_empty") return KW_IS_EMPTY;
+  if (name == "__is_enum") return KW_IS_ENUM;
+  if (name == "__is_final") return KW_IS_FINAL;
+  if (name == "__is_fundamental") return KW_IS_FUNDAMENTAL;
+  if (name == "__is_pod") return KW_IS_POD;
+  if (name == "__is_polymorphic") return KW_IS_POLYMORPHIC;
+  if (name == "__is_standard_layout") return KW_IS_STANDARD_LAYOUT;
+  if (name == "__is_trivial") return KW_IS_TRIVIAL;
+  if (name == "__is_union") return KW_IS_UNION;
   if (name == "long") return KW_LONG;
   if (name == "long") return KW_LONG;
   if (name == "__make_map_property") return KW_MAKE_MAP_PROPERTY;
   if (name == "__make_map_property") return KW_MAKE_MAP_PROPERTY;
   if (name == "__make_property") return KW_MAKE_PROPERTY;
   if (name == "__make_property") return KW_MAKE_PROPERTY;
@@ -2490,6 +2646,7 @@ check_keyword(const string &name) {
   if (name == "typedef") return KW_TYPEDEF;
   if (name == "typedef") return KW_TYPEDEF;
   if (name == "typeid") return KW_TYPEID;
   if (name == "typeid") return KW_TYPEID;
   if (name == "typename") return KW_TYPENAME;
   if (name == "typename") return KW_TYPENAME;
+  if (name == "__underlying_type") return KW_UNDERLYING_TYPE;
   if (name == "union") return KW_UNION;
   if (name == "union") return KW_UNION;
   if (name == "unsigned") return KW_UNSIGNED;
   if (name == "unsigned") return KW_UNSIGNED;
   if (name == "using") return KW_USING;
   if (name == "using") return KW_USING;
@@ -2751,7 +2908,7 @@ nested_parse_template_instantiation(CPPTemplateScope *scope) {
   _parsing_template_params = true;
   _parsing_template_params = true;
 
 
   CPPToken token = internal_get_next_token();
   CPPToken token = internal_get_next_token();
-  if (token._token == '>') {
+  if (token._token == '>' || token._token == 0) {
     _parsing_template_params = false;
     _parsing_template_params = false;
   } else {
   } else {
     _saved_tokens.push_back(token);
     _saved_tokens.push_back(token);
@@ -2760,36 +2917,53 @@ nested_parse_template_instantiation(CPPTemplateScope *scope) {
   CPPTemplateParameterList *actual_params = new CPPTemplateParameterList;
   CPPTemplateParameterList *actual_params = new CPPTemplateParameterList;
 
 
   for (pi = formal_params._parameters.begin();
   for (pi = formal_params._parameters.begin();
-       pi != formal_params._parameters.end() && _parsing_template_params;
-       ++pi) {
+       pi != formal_params._parameters.end() && _parsing_template_params;) {
     CPPToken token = peek_next_token();
     CPPToken token = peek_next_token();
     YYLTYPE loc = token._lloc;
     YYLTYPE loc = token._lloc;
 
 
     CPPDeclaration *decl = (*pi);
     CPPDeclaration *decl = (*pi);
-    if (decl->as_type()) {
+    CPPClassTemplateParameter *param = decl->as_class_template_parameter();
+    CPPInstance *inst = decl->as_instance();
+    if (param) {
       // Parse a typename template parameter.
       // Parse a typename template parameter.
       _saved_tokens.push_back(CPPToken(START_TYPE));
       _saved_tokens.push_back(CPPToken(START_TYPE));
       CPPType *type = ::parse_type(this, current_scope, global_scope);
       CPPType *type = ::parse_type(this, current_scope, global_scope);
       if (type == NULL) {
       if (type == NULL) {
         loc.last_line = get_line_number();
         loc.last_line = get_line_number();
         loc.last_column = get_col_number() - 1;
         loc.last_column = get_col_number() - 1;
-        warning("Invalid type", loc);
+        warning("invalid type", loc);
         skip_to_end_nested();
         skip_to_end_nested();
         type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
         type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
       }
       }
       actual_params->_parameters.push_back(type);
       actual_params->_parameters.push_back(type);
-    } else {
+
+      // If this is a variadic template, keep reading using this parameter.
+      if (!param->_packed) {
+        ++pi;
+      }
+    } else if (inst) {
       // Parse a constant expression template parameter.
       // Parse a constant expression template parameter.
       _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
       _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
       CPPExpression *expr = parse_const_expr(this, current_scope, global_scope);
       CPPExpression *expr = parse_const_expr(this, current_scope, global_scope);
       if (expr == NULL) {
       if (expr == NULL) {
         loc.last_line = get_line_number();
         loc.last_line = get_line_number();
         loc.last_column = get_col_number() - 1;
         loc.last_column = get_col_number() - 1;
-        warning("Invalid expression", loc);
+        warning("invalid expression", loc);
         skip_to_end_nested();
         skip_to_end_nested();
         expr = new CPPExpression(0);
         expr = new CPPExpression(0);
       }
       }
       actual_params->_parameters.push_back(expr);
       actual_params->_parameters.push_back(expr);
+
+      // If this is a variadic template, keep reading using this parameter.
+      if ((inst->_storage_class & CPPInstance::SC_parameter_pack) == 0) {
+        ++pi;
+      }
+    } else {
+      loc.last_line = get_line_number();
+      loc.last_column = get_col_number() - 1;
+      warning("invalid template parameter", loc);
+      skip_to_end_nested();
+      ++pi;
     }
     }
 
 
     _state = S_nested;
     _state = S_nested;

+ 6 - 0
dtool/src/cppparser/cppPreprocessor.h

@@ -72,6 +72,9 @@ public:
   typedef map<string, CPPManifest *> Manifests;
   typedef map<string, CPPManifest *> Manifests;
   Manifests _manifests;
   Manifests _manifests;
 
 
+  typedef pvector<CPPManifest *> ManifestStack;
+  map<string, ManifestStack> _manifest_stack;
+
   pvector<CPPFile::Source> _quote_include_kind;
   pvector<CPPFile::Source> _quote_include_kind;
   DSearchPath _quote_include_path;
   DSearchPath _quote_include_path;
   DSearchPath _angle_include_path;
   DSearchPath _angle_include_path;
@@ -140,6 +143,8 @@ private:
   void handle_error_directive(const string &args, const YYLTYPE &loc);
   void handle_error_directive(const string &args, const YYLTYPE &loc);
 
 
   void skip_false_if_block(bool consider_elifs);
   void skip_false_if_block(bool consider_elifs);
+  bool is_manifest_defined(const string &manifest_name);
+  bool find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source);
 
 
   CPPToken get_quoted_char(int c);
   CPPToken get_quoted_char(int c);
   CPPToken get_quoted_string(int c);
   CPPToken get_quoted_string(int c);
@@ -150,6 +155,7 @@ private:
   void extract_manifest_args(const string &name, int num_args,
   void extract_manifest_args(const string &name, int num_args,
                              int va_arg, vector_string &args);
                              int va_arg, vector_string &args);
   void expand_defined_function(string &expr, size_t q, size_t &p);
   void expand_defined_function(string &expr, size_t q, size_t &p);
+  void expand_has_include_function(string &expr, size_t q, size_t &p, YYLTYPE loc);
   void expand_manifest_inline(string &expr, size_t q, size_t &p,
   void expand_manifest_inline(string &expr, size_t q, size_t &p,
                               const CPPManifest *manifest);
                               const CPPManifest *manifest);
   void extract_manifest_args_inline(const string &name, int num_args,
   void extract_manifest_args_inline(const string &name, int num_args,

+ 79 - 0
dtool/src/cppparser/cppReferenceType.cxx

@@ -12,6 +12,8 @@
  */
  */
 
 
 #include "cppReferenceType.h"
 #include "cppReferenceType.h"
+#include "cppTypedefType.h"
+#include "cppStructType.h"
 
 
 /**
 /**
  *
  *
@@ -87,6 +89,14 @@ is_tbd() const {
   return _pointing_at->is_tbd();
   return _pointing_at->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPReferenceType::
+is_standard_layout() const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -95,6 +105,67 @@ is_trivial() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPReferenceType::
+is_constructible(const CPPType *given_type) const {
+  const CPPType *a;
+  const CPPType *b;
+
+  CPPReferenceType *ref_type = ((CPPType *)given_type)->as_reference_type();
+  if (ref_type != NULL) {
+    if (ref_type->_value_category == VC_rvalue) {
+      return is_constructible(ref_type->_pointing_at);
+    }
+
+    if (_value_category == VC_rvalue) {
+      // Can never initialize an rvalue ref from an lvalue ref.
+      return false;
+    }
+
+    if (!_pointing_at->is_const()) {
+      // Cannot initialize a non-const reference using a const one.
+      if (ref_type->_pointing_at->is_const()) {
+        return false;
+      }
+    }
+
+    a = _pointing_at->remove_cv();
+    b = ref_type->_pointing_at->remove_cv();
+
+  } else {
+    // Initializing using an rvalue.
+    if (!_pointing_at->is_const()) {
+      // Cannot initialize a non-const reference using a const one.
+      if (given_type->is_const()) {
+        return false;
+      }
+
+      // Cannot initalise a non-const lvalue reference with an rvalue ref.
+      if (_value_category == VC_lvalue) {
+        return false;
+      }
+    }
+
+    a = _pointing_at->remove_cv();
+    b = ((CPPType *)given_type)->remove_cv();
+  }
+
+  if (a == b || *a == *b) {
+    return true;
+  }
+
+  // Can initialize from derived class pointer.
+  const CPPStructType *a_struct = a->as_struct_type();
+  const CPPStructType *b_struct = b->as_struct_type();
+  if (a_struct != NULL && b_struct != NULL) {
+    return a_struct->is_base_of(b_struct);
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -111,6 +182,14 @@ is_copy_constructible() const {
   return (_value_category == VC_lvalue);
   return (_value_category == VC_lvalue);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPReferenceType::
+is_destructible() const {
+  return false;
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

+ 3 - 0
dtool/src/cppparser/cppReferenceType.h

@@ -42,9 +42,12 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 1 - 1
dtool/src/cppparser/cppScope.cxx

@@ -27,8 +27,8 @@
 #include "cppPreprocessor.h"
 #include "cppPreprocessor.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
 #include "cppClassTemplateParameter.h"
 #include "cppClassTemplateParameter.h"
-#include "cppConstType.h"
 #include "cppFunctionType.h"
 #include "cppFunctionType.h"
+#include "cppConstType.h"
 #include "cppUsing.h"
 #include "cppUsing.h"
 #include "cppBisonDefs.h"
 #include "cppBisonDefs.h"
 #include "indent.h"
 #include "indent.h"

+ 3 - 2
dtool/src/cppparser/cppScope.h

@@ -139,11 +139,12 @@ public:
   Templates _templates;
   Templates _templates;
   CPPNameComponent _name;
   CPPNameComponent _name;
 
 
+  typedef set<CPPScope *> Using;
+  Using _using;
+
 protected:
 protected:
   CPPScope *_parent_scope;
   CPPScope *_parent_scope;
   CPPStructType *_struct_type;
   CPPStructType *_struct_type;
-  typedef set<CPPScope *> Using;
-  Using _using;
   CPPVisibility _current_vis;
   CPPVisibility _current_vis;
 
 
 private:
 private:

+ 53 - 0
dtool/src/cppparser/cppSimpleType.cxx

@@ -34,6 +34,30 @@ is_tbd() const {
   return (_type == T_unknown);
   return (_type == T_unknown);
 }
 }
 
 
+/**
+ * Returns true if the type is a boolean, floating point or integral type.
+ */
+bool CPPSimpleType::
+is_arithmetic() const {
+  return (_type > T_unknown && _type < T_void);
+}
+
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPSimpleType::
+is_fundamental() const {
+  return (_type != T_unknown && _type != T_parameter && _type != T_auto);
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPSimpleType::
+is_standard_layout() const {
+  return (_type != T_unknown && _type != T_parameter && _type != T_auto);
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -42,6 +66,27 @@ is_trivial() const {
   return true;
   return true;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPSimpleType::
+is_constructible(const CPPType *given_type) const {
+  given_type = ((CPPType *)given_type)->remove_reference()->remove_cv();
+
+  const CPPSimpleType *simple_type = given_type->as_simple_type();
+  if (simple_type == NULL) {
+    return given_type->is_enum() && is_arithmetic();
+  } else if (_type == T_nullptr) {
+    return simple_type->_type == T_nullptr;
+  } else if (_type == T_bool) {
+    return simple_type->is_arithmetic() || simple_type->_type == T_nullptr;
+  } else if (is_arithmetic()) {
+    return simple_type->is_arithmetic();
+  } else {
+    return false;
+  }
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -58,6 +103,14 @@ is_copy_constructible() const {
   return (_type != T_void);
   return (_type != T_void);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPSimpleType::
+is_destructible() const {
+  return (_type != T_void);
+}
+
 /**
 /**
  * Returns true if the type is a special parameter expression type.
  * Returns true if the type is a special parameter expression type.
  *
  *

+ 11 - 7
dtool/src/cppparser/cppSimpleType.h

@@ -19,7 +19,7 @@
 #include "cppType.h"
 #include "cppType.h"
 
 
 /**
 /**
- *
+ * Represents a C++ fundamental type.
  */
  */
 class CPPSimpleType : public CPPType {
 class CPPSimpleType : public CPPType {
 public:
 public:
@@ -40,12 +40,11 @@ public:
     // nullptr_t, which is a typedef of decltype(nullptr).
     // nullptr_t, which is a typedef of decltype(nullptr).
     T_nullptr,
     T_nullptr,
 
 
-/*
- * T_parameter is a special type which is assigned to expressions that are
- * discovered where a formal parameter was expected.  This is a special case
- * for handling cases like this: int foo(0); which really means the same thing
- * as: int foo = 0; but it initially looks like a function prototype.
- */
+    // T_parameter is a special type which is assigned to expressions that are
+    // discovered where a formal parameter was expected.  This is a special
+    // case for handling cases like this: int foo(0); which really means the
+    // same thing as: int foo = 0; but it initially looks like a function
+    // prototype.
     T_parameter,
     T_parameter,
 
 
     // T_auto is also a special type that corresponds to the "auto" keyword
     // T_auto is also a special type that corresponds to the "auto" keyword
@@ -69,9 +68,14 @@ public:
   int _flags;
   int _flags;
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  bool is_arithmetic() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_parameter_expr() const;
   virtual bool is_parameter_expr() const;
 
 
   virtual string get_preferred_name() const;
   virtual string get_preferred_name() const;

+ 379 - 39
dtool/src/cppparser/cppStructType.cxx

@@ -13,6 +13,7 @@
 
 
 #include "cppStructType.h"
 #include "cppStructType.h"
 #include "cppTypedefType.h"
 #include "cppTypedefType.h"
+#include "cppReferenceType.h"
 #include "cppScope.h"
 #include "cppScope.h"
 #include "cppTypeProxy.h"
 #include "cppTypeProxy.h"
 #include "cppTemplateScope.h"
 #include "cppTemplateScope.h"
@@ -126,16 +127,154 @@ is_abstract() const {
   return !funcs.empty();
   return !funcs.empty();
 }
 }
 
 
+/**
+ * Returns true if this struct declaration is a base class of the other given
+ * class, or the same class.
+ */
+bool CPPStructType::
+is_base_of(const CPPStructType *other) const {
+  if (this == other) {
+    return true;
+  }
+  Derivation::const_iterator di;
+  for (di = other->_derivation.begin(); di != other->_derivation.end(); ++di) {
+    const CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && is_base_of(base)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Returns true if this struct declaration defines no non-static data members
+ * other than bit-fields of size 0, no virtual functions, no virtual base
+ * classes, and no non-empty base classes, and is not a union.
+ */
+bool CPPStructType::
+is_empty() const {
+  if (_type == T_union) {
+    return false;
+  }
+
+  if (check_virtual()) {
+    return false;
+  }
+
+  // Make sure all base classes are empty and non-virtual.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if ((*di)._is_virtual || (base != NULL && !base->is_empty())) {
+      return false;
+    }
+  }
+
+  // Make sure there are no non-static data members.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // Only members with a bit width of 0 are okay.
+    if (instance->_bit_width != 0) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Returns true if this class or any of its base classes have virtual methods.
+ */
+bool CPPStructType::
+is_polymorphic() const {
+  if (_type == T_union) {
+    return false;
+  }
+  return check_virtual();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPStructType::
+is_standard_layout() const {
+  assert(_scope != NULL);
+
+  CPPVisibility member_vis = V_unknown;
+
+  // Make sure all data members have the same vis and are standard layout.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // Finally, check if the data member itself is standard layout.
+    assert(instance->_type != NULL);
+    if (!instance->_type->is_standard_layout()) {
+      return false;
+    }
+
+    if (member_vis == V_unknown) {
+      // The first non-static data member may not be a base class.
+      CPPStructType *struct_type = instance->_type->remove_cv()->as_struct_type();
+      if (struct_type != NULL && struct_type->is_base_of(this)) {
+        return false;
+      }
+      member_vis = instance->_vis;
+
+    } else if (member_vis != instance->_vis) {
+      // All members need to have the same access control.
+      return false;
+    }
+  }
+
+  // Make sure all base classes are standard-layout and non-virtual.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if ((*di)._is_virtual) {
+      return false;
+    }
+
+    // If this class had instance members, all base classes need to be empty.
+    if (member_vis != V_unknown) {
+      if (!base->is_empty()) {
+        return false;
+      }
+    } else {
+      if (!base->is_standard_layout()) {
+        return false;
+      }
+    }
+  }
+
+  // Make sure we have no virtual functions.
+  return !check_virtual();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
 bool CPPStructType::
 bool CPPStructType::
 is_trivial() const {
 is_trivial() const {
-  // Make sure all base classes are trivial.
+  // Make sure all base classes are trivial and non-virtual.
   Derivation::const_iterator di;
   Derivation::const_iterator di;
   for (di = _derivation.begin(); di != _derivation.end(); ++di) {
   for (di = _derivation.begin(); di != _derivation.end(); ++di) {
     CPPStructType *base = (*di)._base->as_struct_type();
     CPPStructType *base = (*di)._base->as_struct_type();
-    if (base != NULL && !base->is_trivial()) {
+    if ((*di)._is_virtual || (base != NULL && !base->is_trivial())) {
       return false;
       return false;
     }
     }
   }
   }
@@ -166,7 +305,7 @@ is_trivial() const {
     }
     }
   }
   }
 
 
-  // Now look for functions that are virtual or condestructors.
+  // Now look for functions that are virtual or con/destructors.
   bool is_default_constructible = true;
   bool is_default_constructible = true;
   CPPScope::Functions::const_iterator fi;
   CPPScope::Functions::const_iterator fi;
   for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
   for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
@@ -193,8 +332,8 @@ is_trivial() const {
       if (ftype->_flags & (CPPFunctionType::F_destructor |
       if (ftype->_flags & (CPPFunctionType::F_destructor |
                            CPPFunctionType::F_move_constructor |
                            CPPFunctionType::F_move_constructor |
                            CPPFunctionType::F_copy_constructor)) {
                            CPPFunctionType::F_copy_constructor)) {
-        // User-provided destructors and copymove constructors are not trivial
-        // unless they are defaulted (and not virtual).
+        // User-provided destructors and copy/move constructors are not
+        // trivial unless they are defaulted (and not virtual).
         return false;
         return false;
       }
       }
 
 
@@ -220,6 +359,66 @@ is_trivial() const {
   return is_default_constructible;
   return is_default_constructible;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ * This implementation is rudimentary, as it does not attempt to follow all of
+ * the implicit type conversion rules, but it is still useful.
+ */
+bool CPPStructType::
+is_constructible(const CPPType *given_type) const {
+  // Does the type match the copy constructor or move constructor?
+  CPPType *base_type = ((CPPType *)given_type)->remove_reference();
+  if (is_equivalent(*base_type->remove_cv())) {
+    const CPPReferenceType *ref_type = given_type->as_reference_type();
+    if (ref_type == NULL ||
+        ref_type->_value_category == CPPReferenceType::VC_rvalue) {
+      return is_move_constructible(V_public);
+    } else {
+      return is_copy_constructible(V_public);
+    }
+  }
+
+  if (is_abstract()) {
+    return false;
+  }
+
+  // Check for a different constructor.
+  CPPFunctionGroup *fgroup = get_constructor();
+  if (fgroup != (CPPFunctionGroup *)NULL) {
+    CPPFunctionGroup::Instances::const_iterator ii;
+    for (ii = fgroup->_instances.begin();
+        ii != fgroup->_instances.end();
+        ++ii) {
+      CPPInstance *inst = (*ii);
+      assert(inst->_type != (CPPType *)NULL);
+
+      CPPFunctionType *ftype = inst->_type->as_function_type();
+      assert(ftype != (CPPFunctionType *)NULL);
+
+      CPPParameterList *params = ftype->_parameters;
+      if (params->_parameters.size() == 1 && !params->_includes_ellipsis) {
+        CPPType *param_type = params->_parameters[0]->_type->remove_reference();
+
+        if (!param_type->is_const() && base_type->is_const()) {
+          // Can't pass a const object to a function taking a non-const.
+          continue;
+        }
+
+        // It's deleted, anyhow.
+        if ((inst->_storage_class & CPPInstance::SC_deleted) != 0) {
+          continue;
+        }
+
+        if (param_type->is_equivalent(*base_type)) {
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -236,11 +435,23 @@ is_copy_constructible() const {
   return is_copy_constructible(V_public);
   return is_copy_constructible(V_public);
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPStructType::
+is_destructible() const {
+  return is_destructible(V_public);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
 bool CPPStructType::
 bool CPPStructType::
 is_default_constructible(CPPVisibility min_vis) const {
 is_default_constructible(CPPVisibility min_vis) const {
+  if (is_abstract()) {
+    return false;
+  }
+
   CPPInstance *constructor = get_default_constructor();
   CPPInstance *constructor = get_default_constructor();
   if (constructor != (CPPInstance *)NULL) {
   if (constructor != (CPPInstance *)NULL) {
     // It has a default constructor.
     // It has a default constructor.
@@ -295,24 +506,6 @@ is_default_constructible(CPPVisibility min_vis) const {
     }
     }
   }
   }
 
 
-  // Check that we don't have pure virtual methods.
-  CPPScope::Functions::const_iterator fi;
-  for (fi = _scope->_functions.begin();
-       fi != _scope->_functions.end();
-       ++fi) {
-    CPPFunctionGroup *fgroup = (*fi).second;
-    CPPFunctionGroup::Instances::const_iterator ii;
-    for (ii = fgroup->_instances.begin();
-         ii != fgroup->_instances.end();
-         ++ii) {
-      CPPInstance *inst = (*ii);
-      if (inst->_storage_class & CPPInstance::SC_pure_virtual) {
-        // Here's a pure virtual function.
-        return false;
-      }
-    }
-  }
-
   return true;
   return true;
 }
 }
 
 
@@ -321,6 +514,10 @@ is_default_constructible(CPPVisibility min_vis) const {
  */
  */
 bool CPPStructType::
 bool CPPStructType::
 is_copy_constructible(CPPVisibility min_vis) const {
 is_copy_constructible(CPPVisibility min_vis) const {
+  if (is_abstract()) {
+    return false;
+  }
+
   CPPInstance *constructor = get_copy_constructor();
   CPPInstance *constructor = get_copy_constructor();
   if (constructor != (CPPInstance *)NULL) {
   if (constructor != (CPPInstance *)NULL) {
     // It has a copy constructor.
     // It has a copy constructor.
@@ -378,25 +575,144 @@ is_copy_constructible(CPPVisibility min_vis) const {
     }
     }
   }
   }
 
 
-  // Check that we don't have pure virtual methods.
+  return true;
+}
+
+/**
+ * Returns true if the type is move-constructible.
+ */
+bool CPPStructType::
+is_move_constructible(CPPVisibility min_vis) const {
+  CPPInstance *constructor = get_move_constructor();
+  if (constructor != (CPPInstance *)NULL) {
+    // It has a user-declared move constructor.
+    if (constructor->_vis > min_vis) {
+      // Inaccessible move constructor.
+      return false;
+    }
+
+    if (constructor->_storage_class & CPPInstance::SC_deleted) {
+      // It is deleted.
+      return false;
+    }
+
+    if (is_abstract()) {
+      return false;
+    }
+
+    return true;
+  }
+
+  return is_copy_constructible(min_vis);
+}
+
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPStructType::
+is_destructible(CPPVisibility min_vis) const {
+  // Do we have an explicit destructor?
+  CPPInstance *destructor = get_destructor();
+  if (destructor != (CPPInstance *)NULL) {
+    if (destructor->_vis > min_vis) {
+      // Yes, but it's inaccessible.
+      return false;
+    }
+
+    if (destructor->_storage_class & CPPInstance::SC_deleted) {
+      // Yes, but it's explicitly been deleted.
+      return false;
+    }
+
+    return true;
+  }
+
+  // Make sure all base classes are destructible.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && !base->is_destructible(V_protected)) {
+      return false;
+    }
+  }
+
+  assert(_scope != NULL);
+
+  // Make sure all members are destructible.
+  CPPScope::Variables::const_iterator vi;
+  for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) {
+    CPPInstance *instance = (*vi).second;
+    assert(instance != NULL);
+
+    if (instance->_storage_class & CPPInstance::SC_static) {
+      // Static members don't count.
+      continue;
+    }
+
+    // If the data member is not destructible, no go.
+    assert(instance->_type != NULL);
+    if (!instance->_type->is_destructible()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPStructType::
+is_convertible_to(const CPPType *other) const {
+  if (CPPType::is_convertible_to(other)) {
+    return true;
+  }
+
+  // Check all typecast operators to see whether we can cast to a type that is
+  // convertible to the other type.
   CPPScope::Functions::const_iterator fi;
   CPPScope::Functions::const_iterator fi;
-  for (fi = _scope->_functions.begin();
-       fi != _scope->_functions.end();
-       ++fi) {
+  for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) {
     CPPFunctionGroup *fgroup = (*fi).second;
     CPPFunctionGroup *fgroup = (*fi).second;
+
     CPPFunctionGroup::Instances::const_iterator ii;
     CPPFunctionGroup::Instances::const_iterator ii;
-    for (ii = fgroup->_instances.begin();
-         ii != fgroup->_instances.end();
-         ++ii) {
+    for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) {
       CPPInstance *inst = (*ii);
       CPPInstance *inst = (*ii);
-      if (inst->_storage_class & CPPInstance::SC_pure_virtual) {
-        // Here's a pure virtual function.
-        return false;
+
+      if (inst->_storage_class & (CPPInstance::SC_deleted | CPPInstance::SC_static | CPPInstance::SC_explicit)) {
+        // Exclude static/deleted/explicit methods.
+        continue;
+      }
+
+      // Also, the instance needs to be publicly visible.
+      if (inst->_vis > V_public) {
+        continue;
+      }
+
+      assert(inst->_type != (CPPType *)NULL);
+      CPPFunctionType *ftype = inst->_type->as_function_type();
+      assert(ftype != (CPPFunctionType *)NULL);
+
+      if (ftype->_return_type != NULL &&
+          (ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
+        // Yes, this is a typecast operator.  Test using the return type.
+        if (ftype->_return_type->is_convertible_to(other)) {
+          return true;
+        }
       }
       }
     }
     }
   }
   }
 
 
-  return true;
+  // Check whether any of the base classes are convertible.
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && (*di)._vis <= V_public && !base->is_convertible_to(other)) {
+      return true;
+    }
+  }
+
+  return false;
 }
 }
 
 
 /**
 /**
@@ -420,6 +736,30 @@ check_virtual() const {
   return !funcs.empty();
   return !funcs.empty();
 }
 }
 
 
+/**
+ * Returns true if this class, or any of its base classes, has a virtual
+ * destructor.
+ */
+bool CPPStructType::
+has_virtual_destructor() const {
+  CPPInstance *destructor = get_destructor();
+  if (destructor != NULL) {
+    if (destructor->_storage_class & CPPInstance::SC_virtual) {
+      return true;
+    }
+  }
+
+  Derivation::const_iterator di;
+  for (di = _derivation.begin(); di != _derivation.end(); ++di) {
+    CPPStructType *base = (*di)._base->as_struct_type();
+    if (base != NULL && base->has_virtual_destructor()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 /**
 /**
  * Returns true if this declaration is an actual, factual declaration, or
  * Returns true if this declaration is an actual, factual declaration, or
  * false if some part of the declaration depends on a template parameter which
  * false if some part of the declaration depends on a template parameter which
@@ -459,7 +799,7 @@ get_constructor() const {
 
 
 /**
 /**
  * Returns the default constructor defined for the struct type, or NULL if
  * Returns the default constructor defined for the struct type, or NULL if
- * there is none.
+ * there is no user-declared constructor that takes 0 arguments.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_default_constructor() const {
 get_default_constructor() const {
@@ -490,7 +830,7 @@ get_default_constructor() const {
 
 
 /**
 /**
  * Returns the copy constructor defined for the struct type, or NULL if no
  * Returns the copy constructor defined for the struct type, or NULL if no
- * copy constructor exists.
+ * user-declared copy constructor exists.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_copy_constructor() const {
 get_copy_constructor() const {
@@ -519,7 +859,7 @@ get_copy_constructor() const {
 
 
 /**
 /**
  * Returns the move constructor defined for the struct type, or NULL if no
  * Returns the move constructor defined for the struct type, or NULL if no
- * move constructor exists.
+ * user-declared move constructor exists.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_move_constructor() const {
 get_move_constructor() const {
@@ -548,7 +888,7 @@ get_move_constructor() const {
 
 
 /**
 /**
  * Returns the destructor defined for the struct type, if any, or NULL if no
  * Returns the destructor defined for the struct type, if any, or NULL if no
- * destructor is found.
+ * user-declared destructor is found.
  */
  */
 CPPInstance *CPPStructType::
 CPPInstance *CPPStructType::
 get_destructor() const {
 get_destructor() const {
@@ -854,7 +1194,7 @@ get_virtual_funcs(VFunctions &funcs) const {
           CPPFunctionType *new_ftype = new_inst->_type->as_function_type();
           CPPFunctionType *new_ftype = new_inst->_type->as_function_type();
           assert(new_ftype != (CPPFunctionType *)NULL);
           assert(new_ftype != (CPPFunctionType *)NULL);
 
 
-          if (new_ftype->is_equivalent_function(*base_ftype)) {
+          if (new_ftype->match_virtual_override(*base_ftype)) {
             // It's a match!  We now know it's virtual.  Erase this function
             // It's a match!  We now know it's virtual.  Erase this function
             // from the list, so we can add it back in below.
             // from the list, so we can add it back in below.
             funcs.erase(vfi);
             funcs.erase(vfi);

+ 12 - 0
dtool/src/cppparser/cppStructType.h

@@ -44,14 +44,26 @@ public:
   CPPScope *get_scope() const;
   CPPScope *get_scope() const;
 
 
   bool is_abstract() const;
   bool is_abstract() const;
+  bool is_base_of(const CPPStructType *other) const;
+  bool is_empty() const;
+  bool is_polymorphic() const;
   bool check_virtual() const;
   bool check_virtual() const;
+  bool has_virtual_destructor() const;
   virtual bool is_fully_specified() const;
   virtual bool is_fully_specified() const;
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *arg_type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   bool is_default_constructible(CPPVisibility min_vis) const;
   bool is_default_constructible(CPPVisibility min_vis) const;
   bool is_copy_constructible(CPPVisibility min_vis) const;
   bool is_copy_constructible(CPPVisibility min_vis) const;
+  bool is_move_constructible(CPPVisibility min_vis) const;
+  bool is_destructible(CPPVisibility min_vis) const;
+  virtual bool is_convertible_to(const CPPType *other) const;
+
+  inline bool is_final() const { return _final; }
 
 
   CPPFunctionGroup *get_constructor() const;
   CPPFunctionGroup *get_constructor() const;
   CPPInstance *get_default_constructor() const;
   CPPInstance *get_default_constructor() const;

+ 4 - 2
dtool/src/cppparser/cppTemplateScope.cxx

@@ -97,8 +97,10 @@ add_template_parameter(CPPDeclaration *param) {
   CPPClassTemplateParameter *cl = param->as_class_template_parameter();
   CPPClassTemplateParameter *cl = param->as_class_template_parameter();
   if (cl != NULL) {
   if (cl != NULL) {
     // Create an implicit typedef for this class parameter.
     // Create an implicit typedef for this class parameter.
-    string name = cl->_ident->get_local_name();
-    _types[name] = cl;
+    if (cl->_ident != NULL) {
+      string name = cl->_ident->get_local_name();
+      _types[name] = cl;
+    }
   }
   }
 
 
   CPPInstance *inst = param->as_instance();
   CPPInstance *inst = param->as_instance();

+ 175 - 0
dtool/src/cppparser/cppType.cxx

@@ -12,7 +12,12 @@
  */
  */
 
 
 #include "cppType.h"
 #include "cppType.h"
+#include "cppConstType.h"
+#include "cppPointerType.h"
+#include "cppReferenceType.h"
+#include "cppStructType.h"
 #include "cppTypedefType.h"
 #include "cppTypedefType.h"
+#include "cppExtensionType.h"
 #include <algorithm>
 #include <algorithm>
 
 
 CPPType::Types CPPType::_types;
 CPPType::Types CPPType::_types;
@@ -57,6 +62,22 @@ is_tbd() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPType::
+is_fundamental() const {
+  return false;
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPType::
+is_standard_layout() const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -65,6 +86,14 @@ is_trivial() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPType::
+is_constructible(const CPPType *given_type) const {
+  return false;
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -81,6 +110,14 @@ is_copy_constructible() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPType::
+is_destructible() const {
+  return !is_incomplete();
+}
+
 /**
 /**
  * Returns true if the type is a special parameter expression type.
  * Returns true if the type is a special parameter expression type.
  *
  *
@@ -92,6 +129,136 @@ is_parameter_expr() const {
   return false;
   return false;
 }
 }
 
 
+/**
+ * Returns true if this is an enum type, or a typedef to an enum type.
+ */
+bool CPPType::
+is_enum() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_enum();
+  }
+  const CPPExtensionType *ext_type = as_extension_type();
+  if (ext_type != NULL) {
+    return ext_type->_type == CPPExtensionType::T_enum ||
+           ext_type->_type == CPPExtensionType::T_enum_struct ||
+           ext_type->_type == CPPExtensionType::T_enum_class;
+  }
+  return false;
+}
+
+/**
+ * Returns true if this is a const type, or a typedef to a const type.
+ */
+bool CPPType::
+is_const() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_const();
+  }
+  return get_subtype() == ST_const;
+}
+
+/**
+ * Returns true if this is a reference type, or a typedef to a reference type.
+ */
+bool CPPType::
+is_reference() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_reference();
+  }
+  return get_subtype() == ST_reference;
+}
+
+/**
+ * Returns true if this is an unqualified or cv-qualified pointer type, or a
+ * typedef to one.
+ */
+bool CPPType::
+is_pointer() const {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    return td_type->_type->is_pointer();
+  }
+  const CPPConstType *const_type = as_const_type();
+  if (const_type != NULL) {
+    return const_type->_wrapped_around->is_pointer();
+  }
+  return get_subtype() == ST_pointer;
+}
+
+/**
+ * Returns the type with any const qualifier stripped off.  Will follow
+ * typedefs, but only if necessary.
+ */
+CPPType *CPPType::
+remove_const() {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    CPPType *unwrapped = td_type->_type->remove_const();
+    if (unwrapped != td_type->_type) {
+      return unwrapped;
+    } else {
+      return this;
+    }
+  }
+  const CPPConstType *const_type = as_const_type();
+  if (const_type != NULL) {
+    return const_type->_wrapped_around->remove_const();
+  }
+  return this;
+}
+
+/**
+ * Returns the type with any reference stripped off.
+ */
+CPPType *CPPType::
+remove_reference() {
+  const CPPTypedefType *td_type = as_typedef_type();
+  if (td_type != NULL) {
+    CPPType *unwrapped = td_type->_type->remove_reference();
+    if (unwrapped != td_type->_type) {
+      return unwrapped;
+    } else {
+      return this;
+    }
+  }
+  const CPPReferenceType *ref_type = as_reference_type();
+  if (ref_type != NULL) {
+    return ref_type->_pointing_at;
+  }
+  return this;
+}
+
+/**
+ * Returns the type with any pointer and cv-qualifiers stripped off.
+ */
+CPPType *CPPType::
+remove_pointer() {
+  switch (get_subtype()) {
+  case ST_typedef:
+    {
+      const CPPTypedefType *td_type = as_typedef_type();
+      CPPType *unwrapped = td_type->_type->remove_pointer();
+      if (unwrapped != td_type->_type) {
+        return unwrapped;
+      } else {
+        return this;
+      }
+    }
+
+  case ST_pointer:
+    return ((const CPPPointerType *)this)->_pointing_at;
+
+  case ST_const:
+    return ((const CPPConstType *)this)->_wrapped_around->remove_pointer();
+
+  default:
+    return this;
+  }
+}
+
 /**
 /**
  * Returns true if the type has even been typedef'ed and therefore has a
  * Returns true if the type has even been typedef'ed and therefore has a
  * simple name available to stand for it.  Extension types are all implicitly
  * simple name available to stand for it.  Extension types are all implicitly
@@ -229,6 +396,14 @@ is_equivalent(const CPPType &other) const {
   return is_equal(&other);
   return is_equal(&other);
 }
 }
 
 
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPType::
+is_convertible_to(const CPPType *other) const {
+  return other->is_constructible(this);
+}
 
 
 /**
 /**
  * Formats a C++-looking line that defines an instance of the given type, with
  * Formats a C++-looking line that defines an instance of the given type, with

+ 17 - 0
dtool/src/cppparser/cppType.h

@@ -45,11 +45,27 @@ public:
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
   virtual bool is_parameter_expr() const;
   virtual bool is_parameter_expr() const;
 
 
+  // Convenience methods.
+  bool is_enum() const;
+  bool is_const() const;
+  bool is_reference() const;
+  bool is_pointer() const;
+
+  CPPType *remove_const();
+  inline CPPType *remove_volatile() { return this; }
+  inline CPPType *remove_cv() { return remove_const(); };
+  CPPType *remove_reference();
+  CPPType *remove_pointer();
+
   bool has_typedef_name() const;
   bool has_typedef_name() const;
   string get_typedef_name(CPPScope *scope = NULL) const;
   string get_typedef_name(CPPScope *scope = NULL) const;
 
 
@@ -61,6 +77,7 @@ public:
   string get_alt_name(int n) const;
   string get_alt_name(int n) const;
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   void output_instance(ostream &out, const string &name,
   void output_instance(ostream &out, const string &name,

+ 41 - 0
dtool/src/cppparser/cppTypedefType.cxx

@@ -157,6 +157,22 @@ is_tbd() const {
   return _type->is_tbd();
   return _type->is_tbd();
 }
 }
 
 
+/**
+ * Returns true if the type is considered a fundamental type.
+ */
+bool CPPTypedefType::
+is_fundamental() const {
+  return _type->is_fundamental();
+}
+
+/**
+ * Returns true if the type is considered a standard layout type.
+ */
+bool CPPTypedefType::
+is_standard_layout() const {
+  return _type->is_standard_layout();
+}
+
 /**
 /**
  * Returns true if the type is considered a Plain Old Data (POD) type.
  * Returns true if the type is considered a Plain Old Data (POD) type.
  */
  */
@@ -165,6 +181,14 @@ is_trivial() const {
   return _type->is_trivial();
   return _type->is_trivial();
 }
 }
 
 
+/**
+ * Returns true if the type can be constructed using the given argument.
+ */
+bool CPPTypedefType::
+is_constructible(const CPPType *given_type) const {
+  return _type->is_constructible(given_type);
+}
+
 /**
 /**
  * Returns true if the type is default-constructible.
  * Returns true if the type is default-constructible.
  */
  */
@@ -181,6 +205,14 @@ is_copy_constructible() const {
   return _type->is_copy_constructible();
   return _type->is_copy_constructible();
 }
 }
 
 
+/**
+ * Returns true if the type is destructible.
+ */
+bool CPPTypedefType::
+is_destructible() const {
+  return _type->is_destructible();
+}
+
 /**
 /**
  * Returns true if this declaration is an actual, factual declaration, or
  * Returns true if this declaration is an actual, factual declaration, or
  * false if some part of the declaration depends on a template parameter which
  * false if some part of the declaration depends on a template parameter which
@@ -300,6 +332,15 @@ resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
   return this;
   return this;
 }
 }
 
 
+/**
+ * Returns true if variables of this type may be implicitly converted to
+ * the other type.
+ */
+bool CPPTypedefType::
+is_convertible_to(const CPPType *other) const {
+  return _type->is_convertible_to(other);
+}
+
 /**
 /**
  * This is a little more forgiving than is_equal(): it returns true if the
  * This is a little more forgiving than is_equal(): it returns true if the
  * types appear to be referring to the same thing, even if they may have
  * types appear to be referring to the same thing, even if they may have

+ 5 - 0
dtool/src/cppparser/cppTypedefType.h

@@ -42,9 +42,13 @@ public:
 
 
   virtual bool is_incomplete() const;
   virtual bool is_incomplete() const;
   virtual bool is_tbd() const;
   virtual bool is_tbd() const;
+  virtual bool is_fundamental() const;
+  virtual bool is_standard_layout() const;
   virtual bool is_trivial() const;
   virtual bool is_trivial() const;
+  virtual bool is_constructible(const CPPType *type) const;
   virtual bool is_default_constructible() const;
   virtual bool is_default_constructible() const;
   virtual bool is_copy_constructible() const;
   virtual bool is_copy_constructible() const;
+  virtual bool is_destructible() const;
 
 
   virtual bool is_fully_specified() const;
   virtual bool is_fully_specified() const;
 
 
@@ -60,6 +64,7 @@ public:
   virtual CPPType *resolve_type(CPPScope *current_scope,
   virtual CPPType *resolve_type(CPPScope *current_scope,
                                 CPPScope *global_scope);
                                 CPPScope *global_scope);
 
 
+  virtual bool is_convertible_to(const CPPType *other) const;
   virtual bool is_equivalent(const CPPType &other) const;
   virtual bool is_equivalent(const CPPType &other) const;
 
 
   virtual void output(ostream &out, int indent_level, CPPScope *scope,
   virtual void output(ostream &out, int indent_level, CPPScope *scope,

+ 9 - 2
dtool/src/dtoolbase/deletedBufferChain.cxx

@@ -39,7 +39,7 @@ allocate(size_t size, TypeHandle type_handle) {
   assert(size <= _buffer_size);
   assert(size <= _buffer_size);
 
 
   // Determine how much space to allocate.
   // Determine how much space to allocate.
-  const size_t alloc_size = _buffer_size + flag_reserved_bytes;
+  const size_t alloc_size = _buffer_size + flag_reserved_bytes + MemoryHook::get_memory_alignment() - 1;
 
 
   ObjectNode *obj;
   ObjectNode *obj;
 
 
@@ -69,7 +69,10 @@ allocate(size_t size, TypeHandle type_handle) {
   // If we get here, the deleted_chain is empty; we have to allocate a new
   // If we get here, the deleted_chain is empty; we have to allocate a new
   // object from the system pool.
   // object from the system pool.
 
 
-  obj = (ObjectNode *)NeverFreeMemory::alloc(alloc_size);
+  // Allocate memory, and make sure the object starts at the proper alignment.
+  void *mem = NeverFreeMemory::alloc(alloc_size);
+  intptr_t pad = (-(intptr_t)flag_reserved_bytes - (intptr_t)mem) % MemoryHook::get_memory_alignment();
+  obj = (ObjectNode *)((uintptr_t)mem + pad);
 
 
 #ifdef USE_DELETEDCHAINFLAG
 #ifdef USE_DELETEDCHAINFLAG
   obj->_flag = DCF_alive;
   obj->_flag = DCF_alive;
@@ -77,6 +80,10 @@ allocate(size_t size, TypeHandle type_handle) {
 
 
   void *ptr = node_to_buffer(obj);
   void *ptr = node_to_buffer(obj);
 
 
+#ifndef NDEBUG
+  assert(((uintptr_t)ptr % MemoryHook::get_memory_alignment()) == 0);
+#endif
+
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   type_handle.inc_memory_usage(TypeHandle::MC_deleted_chain_active, alloc_size);
   type_handle.inc_memory_usage(TypeHandle::MC_deleted_chain_active, alloc_size);
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE

+ 1 - 5
dtool/src/dtoolbase/deletedBufferChain.h

@@ -95,12 +95,8 @@ private:
   // Without DELETEDCHAINFLAG, we don't even store the _flag member at all.
   // Without DELETEDCHAINFLAG, we don't even store the _flag member at all.
   static const size_t flag_reserved_bytes = 0;
   static const size_t flag_reserved_bytes = 0;
 
 
-#elif defined(LINMATH_ALIGN)
-  // With SSE2 alignment, we need all 16 bytes to preserve alignment.
-  static const size_t flag_reserved_bytes = 16;
-
 #else
 #else
-  // Otherwise, we only need enough space for the Integer itself.
+  // Otherwise, we need space for the integer.
   static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer);
   static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer);
 #endif  // USE_DELETEDCHAINFLAG
 #endif  // USE_DELETEDCHAINFLAG
 
 

+ 6 - 1
dtool/src/dtoolbase/dtoolbase.h

@@ -339,21 +339,26 @@ typedef struct _object PyObject;
 #define ALIGN_4BYTE
 #define ALIGN_4BYTE
 #define ALIGN_8BYTE
 #define ALIGN_8BYTE
 #define ALIGN_16BYTE
 #define ALIGN_16BYTE
+#define ALIGN_32BYTE
 #define ALIGN_64BYTE
 #define ALIGN_64BYTE
 #elif defined(_MSC_VER)
 #elif defined(_MSC_VER)
 #define ALIGN_4BYTE __declspec(align(4))
 #define ALIGN_4BYTE __declspec(align(4))
 #define ALIGN_8BYTE __declspec(align(8))
 #define ALIGN_8BYTE __declspec(align(8))
 #define ALIGN_16BYTE __declspec(align(16))
 #define ALIGN_16BYTE __declspec(align(16))
+#define ALIGN_32BYTE __declspec(align(32))
 #define ALIGN_64BYTE __declspec(align(64))
 #define ALIGN_64BYTE __declspec(align(64))
 #elif defined(__GNUC__)
 #elif defined(__GNUC__)
 #define ALIGN_4BYTE __attribute__ ((aligned (4)))
 #define ALIGN_4BYTE __attribute__ ((aligned (4)))
 #define ALIGN_8BYTE __attribute__ ((aligned (8)))
 #define ALIGN_8BYTE __attribute__ ((aligned (8)))
 #define ALIGN_16BYTE __attribute__ ((aligned (16)))
 #define ALIGN_16BYTE __attribute__ ((aligned (16)))
+#define ALIGN_32BYTE __attribute__ ((aligned (32)))
 #define ALIGN_64BYTE __attribute__ ((aligned (64)))
 #define ALIGN_64BYTE __attribute__ ((aligned (64)))
 #else
 #else
 #define ALIGN_4BYTE
 #define ALIGN_4BYTE
 #define ALIGN_8BYTE
 #define ALIGN_8BYTE
 #define ALIGN_16BYTE
 #define ALIGN_16BYTE
+#define ALIGN_32BYTE
+#define ALIGN_64BYTE
 #endif
 #endif
 
 
 // Do we need to implement memory-alignment enforcement within the MemoryHook
 // Do we need to implement memory-alignment enforcement within the MemoryHook
@@ -374,7 +379,7 @@ typedef struct _object PyObject;
 // externally.
 // externally.
 #define MEMORY_HOOK_DO_ALIGN 1
 #define MEMORY_HOOK_DO_ALIGN 1
 
 
-#elif defined(IS_OSX) || defined(_WIN64)
+#elif (defined(IS_OSX) || defined(_WIN64)) && !defined(__AVX__)
 // The OS-provided malloc implementation will do the required alignment.
 // The OS-provided malloc implementation will do the required alignment.
 #undef MEMORY_HOOK_DO_ALIGN
 #undef MEMORY_HOOK_DO_ALIGN
 
 

+ 16 - 4
dtool/src/dtoolbase/memoryHook.I

@@ -43,10 +43,16 @@ get_memory_alignment() {
 #ifdef LINMATH_ALIGN
 #ifdef LINMATH_ALIGN
   // We require 16-byte alignment of certain structures, to support SSE2.  We
   // We require 16-byte alignment of certain structures, to support SSE2.  We
   // don't strictly have to align *everything*, but it's just easier to do so.
   // don't strictly have to align *everything*, but it's just easier to do so.
+#ifdef __AVX__
+  // Eigen requires 32-byte alignment when using AVX instructions.
+  const size_t alignment_size = 32;
+#else
   const size_t alignment_size = 16;
   const size_t alignment_size = 16;
+#endif
 #else
 #else
-  // Otherwise, use word alignment.
-  const size_t alignment_size = sizeof(void *);
+  // Otherwise, align to two words.  This seems to be pretty standard to the
+  // point where some code may rely on this being the case.
+  const size_t alignment_size = sizeof(void *) * 2;
 #endif
 #endif
   return alignment_size;
   return alignment_size;
 }
 }
@@ -64,7 +70,12 @@ get_header_reserved_bytes() {
 #ifdef LINMATH_ALIGN
 #ifdef LINMATH_ALIGN
   // If we're doing SSE2 alignment, we must reserve a full 16-byte block,
   // If we're doing SSE2 alignment, we must reserve a full 16-byte block,
   // since anything less than that will spoil the alignment.
   // since anything less than that will spoil the alignment.
+#ifdef __AVX__
+  // Eigen requires 32-byte alignment when using AVX instructions.
+  static const size_t header_reserved_bytes = 32;
+#else
   static const size_t header_reserved_bytes = 16;
   static const size_t header_reserved_bytes = 16;
+#endif
 
 
 #elif defined(MEMORY_HOOK_DO_ALIGN)
 #elif defined(MEMORY_HOOK_DO_ALIGN)
   // If we're just aligning to words, we reserve a block as big as two words,
   // If we're just aligning to words, we reserve a block as big as two words,
@@ -72,8 +83,9 @@ get_header_reserved_bytes() {
   static const size_t header_reserved_bytes = sizeof(size_t) + sizeof(size_t);
   static const size_t header_reserved_bytes = sizeof(size_t) + sizeof(size_t);
 
 
 #else
 #else
-  // If we're not aligning, we just need space for the word itself.
-  static const size_t header_reserved_bytes = sizeof(size_t);
+  // Virtually all allocators align to two words, so we make sure we preserve
+  // that alignment for the benefit of anyone who relies upon that.
+  static const size_t header_reserved_bytes = sizeof(void *) * 2;
 #endif
 #endif
 
 
   return header_reserved_bytes;
   return header_reserved_bytes;

+ 5 - 0
dtool/src/dtoolbase/memoryHook.cxx

@@ -53,8 +53,13 @@
 // drose: We require 16-byte alignment of certain structures, to
 // drose: We require 16-byte alignment of certain structures, to
 // support SSE2.  We don't strictly have to align *everything*, but
 // support SSE2.  We don't strictly have to align *everything*, but
 // it's just easier to do so.
 // it's just easier to do so.
+#ifdef __AVX__
+// Eigen requires 32-byte alignment when using AVX instructions.
+#define MALLOC_ALIGNMENT ((size_t)32U)
+#else
 #define MALLOC_ALIGNMENT ((size_t)16U)
 #define MALLOC_ALIGNMENT ((size_t)16U)
 #endif
 #endif
+#endif
 
 
 #include "dlmalloc_src.cxx"
 #include "dlmalloc_src.cxx"
 
 

+ 2 - 0
dtool/src/dtoolbase/neverFreeMemory.I

@@ -14,6 +14,8 @@
 /**
 /**
  * Returns a pointer to a newly-allocated block of memory of the indicated
  * Returns a pointer to a newly-allocated block of memory of the indicated
  * size.
  * size.
+ *
+ * Please note that the resulting pointer is not aligned to any boundary.
  */
  */
 INLINE void *NeverFreeMemory::
 INLINE void *NeverFreeMemory::
 alloc(size_t size) {
 alloc(size_t size) {

+ 3 - 7
dtool/src/dtoolbase/neverFreeMemory.cxx

@@ -39,13 +39,9 @@ void *NeverFreeMemory::
 ns_alloc(size_t size) {
 ns_alloc(size_t size) {
   _lock.acquire();
   _lock.acquire();
 
 
-  // We always allocate integer multiples of this many bytes, to guarantee
-  // this minimum alignment.
-  static const size_t alignment_size = MemoryHook::get_memory_alignment();
-
-  // Round up to the next alignment_size.
-  size = ((size + alignment_size - 1) / alignment_size) * alignment_size;
-
+  //NB: we no longer do alignment here.  The only class that uses this is
+  // DeletedBufferChain, and we can do the alignment potentially more
+  // efficiently there since we don't end up overallocating as much.
   _total_used += size;
   _total_used += size;
 
 
   // Look for a page that has sufficient space remaining.
   // Look for a page that has sufficient space remaining.

+ 0 - 3
dtool/src/dtoolutil/.gitignore

@@ -1,3 +0,0 @@
-/checkPandaVersion.cxx
-/checkPandaVersion.h
-/pandaVersion.h

+ 15 - 10
dtool/src/dtoolutil/filename.I

@@ -38,7 +38,6 @@ Filename(const char *filename) {
   (*this) = filename;
   (*this) = filename;
 }
 }
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -84,6 +83,20 @@ Filename(Filename &&from) NOEXCEPT :
 }
 }
 #endif  // USE_MOVE_SEMANTICS
 #endif  // USE_MOVE_SEMANTICS
 
 
+/**
+ * Creates an empty Filename.
+ */
+INLINE Filename::
+Filename() :
+  _dirname_end(0),
+  _basename_start(0),
+  _basename_end(string::npos),
+  _extension_start(string::npos),
+  _hash_start(string::npos),
+  _hash_end(string::npos),
+  _flags(0) {
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -155,14 +168,6 @@ pattern_filename(const string &filename) {
   return result;
   return result;
 }
 }
 
 
-/**
- *
- */
-INLINE Filename::
-~Filename() {
-}
-
-
 /**
 /**
  *
  *
  */
  */
@@ -233,7 +238,7 @@ operator = (string &&filename) NOEXCEPT {
  */
  */
 INLINE Filename &Filename::
 INLINE Filename &Filename::
 operator = (Filename &&from) NOEXCEPT {
 operator = (Filename &&from) NOEXCEPT {
-  _filename = MOVE(from._filename);
+  _filename = move(from._filename);
   _dirname_end = from._dirname_end;
   _dirname_end = from._dirname_end;
   _basename_start = from._basename_start;
   _basename_start = from._basename_start;
   _basename_end = from._basename_end;
   _basename_end = from._basename_end;

+ 8 - 5
dtool/src/dtoolutil/filename.h

@@ -55,20 +55,22 @@ public:
   };
   };
 
 
   INLINE Filename(const char *filename);
   INLINE Filename(const char *filename);
-
-PUBLISHED:
-  INLINE Filename(const string &filename = "");
+  INLINE Filename(const string &filename);
   INLINE Filename(const wstring &filename);
   INLINE Filename(const wstring &filename);
   INLINE Filename(const Filename &copy);
   INLINE Filename(const Filename &copy);
-  Filename(const Filename &dirname, const Filename &basename);
-  INLINE ~Filename();
 
 
 #ifdef USE_MOVE_SEMANTICS
 #ifdef USE_MOVE_SEMANTICS
   INLINE Filename(string &&filename) NOEXCEPT;
   INLINE Filename(string &&filename) NOEXCEPT;
   INLINE Filename(Filename &&from) NOEXCEPT;
   INLINE Filename(Filename &&from) NOEXCEPT;
 #endif
 #endif
 
 
+PUBLISHED:
+  INLINE Filename();
+  Filename(const Filename &dirname, const Filename &basename);
+
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
+  EXTENSION(Filename(PyObject *path));
+
   EXTENSION(PyObject *__reduce__(PyObject *self) const);
   EXTENSION(PyObject *__reduce__(PyObject *self) const);
 #endif
 #endif
 
 
@@ -118,6 +120,7 @@ PUBLISHED:
   INLINE char operator [] (size_t n) const;
   INLINE char operator [] (size_t n) const;
 
 
   EXTENSION(PyObject *__repr__() const);
   EXTENSION(PyObject *__repr__() const);
+  EXTENSION(PyObject *__fspath__() const);
 
 
   INLINE string substr(size_t begin) const;
   INLINE string substr(size_t begin) const;
   INLINE string substr(size_t begin, size_t end) const;
   INLINE string substr(size_t begin, size_t end) const;

+ 4 - 2
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -2344,7 +2344,7 @@ write_module_class(ostream &out, Object *obj) {
 
 
           string expected_params;
           string expected_params;
 
 
-          out << "  if (arg2 != (PyObject *)NULL) {\n";
+          out << "  if (arg2 != (PyObject *)NULL && arg2 != Py_None) {\n";
           out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
           out << "    PyObject *args = PyTuple_Pack(2, arg, arg2);\n";
           write_function_forset(out, two_param_remaps, 2, 2, expected_params, 4,
           write_function_forset(out, two_param_remaps, 2, 2, expected_params, 4,
                                 true, true, AT_varargs, RF_pyobject | RF_err_null | RF_decref_args, true);
                                 true, true, AT_varargs, RF_pyobject | RF_err_null | RF_decref_args, true);
@@ -6142,7 +6142,7 @@ pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,
 
 
         write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const);
         write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const);
       }
       }
-    } else if (TypeManager::is_struct(orig_type->as_pointer_type()->_pointing_at)) {
+    } else if (TypeManager::is_struct(orig_type->remove_pointer())) {
       TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false);
       TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false);
       const InterrogateType &itype = idb->get_type(type_index);
       const InterrogateType &itype = idb->get_type(type_index);
 
 
@@ -6749,6 +6749,8 @@ is_cpp_type_legal(CPPType *in_ctype) {
     return true;
     return true;
   } else if (TypeManager::is_pointer_to_simple(type)) {
   } else if (TypeManager::is_pointer_to_simple(type)) {
     return true;
     return true;
+  } else if (builder.in_forcetype(type->get_local_name(&parser))) {
+    return true;
   } else if (TypeManager::is_exported(type)) {
   } else if (TypeManager::is_exported(type)) {
     return true;
     return true;
   } else if (TypeManager::is_pointer_to_PyObject(in_ctype)) {
   } else if (TypeManager::is_pointer_to_PyObject(in_ctype)) {

+ 7 - 3
dtool/src/interrogate/interrogateBuilder.cxx

@@ -2401,7 +2401,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
 
 
   cpptype = TypeManager::resolve_type(cpptype)->as_struct_type();
   cpptype = TypeManager::resolve_type(cpptype)->as_struct_type();
   assert(cpptype != (CPPStructType *)NULL);
   assert(cpptype != (CPPStructType *)NULL);
-  bool has_virt_methods = cpptype->check_virtual();
+  bool has_virt_methods = cpptype->is_polymorphic();
 
 
   switch (cpptype->_type) {
   switch (cpptype->_type) {
   case CPPExtensionType::T_class:
   case CPPExtensionType::T_class:
@@ -2501,7 +2501,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
           // (For many compilers, this does not require a pointer change.)
           // (For many compilers, this does not require a pointer change.)
           generate_casts = true;
           generate_casts = true;
 
 
-        } else if (has_virt_methods && (base_type->as_struct_type() == (CPPStructType *)NULL || !base_type->as_struct_type()->check_virtual())) {
+        } else if (has_virt_methods && (base_type->as_struct_type() == (CPPStructType *)NULL || !base_type->as_struct_type()->is_polymorphic())) {
           // Finally, if this class has virtual methods, but its parent
           // Finally, if this class has virtual methods, but its parent
           // doesn't, then we have to upcast (because this class will require
           // doesn't, then we have to upcast (because this class will require
           // space for a virtual function table pointer, while the parent
           // space for a virtual function table pointer, while the parent
@@ -2651,7 +2651,11 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
     }
     }
   }
   }
 
 
-  if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
+  if (!cpptype->is_destructible()) {
+    // There's no way to destruct the type.
+    itype._destructor = 0;
+
+  } else if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
     // If we have inherited our virtual destructor from our base class, go
     // If we have inherited our virtual destructor from our base class, go
     // ahead and assign the same function index.
     // ahead and assign the same function index.
     assert(!itype._derivations.empty());
     assert(!itype._derivations.empty());

+ 153 - 0
dtool/src/parser-inc/functional

@@ -0,0 +1,153 @@
+/**
+ * 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 functional
+ * @author tobspr
+ * @date 2016-11-01
+ */
+
+// This file, and all the other files in this directory, aren't
+// intended to be compiled--they're just parsed by CPPParser (and
+// interrogate) in lieu of the actual system headers, to generate the
+// interrogate database.
+
+#ifndef FUNCTIONAL_H
+#define FUNCTIONAL_H
+
+#include <stddef.h>
+
+namespace std {
+
+  // base (deprecated):
+  template <class Arg, class Result> struct unary_function;
+  template <class Arg1, class Arg2, class Result> struct binary_function;
+ 
+  // reference_wrapper:
+  template <class T> class reference_wrapper;
+
+  // arithmetic operations:
+  template <class T> struct plus;
+  template <class T> struct minus;
+  template <class T> struct multiplies;
+  template <class T> struct divides;
+  template <class T> struct modulus;
+  template <class T> struct negate;
+ 
+  // comparisons:
+  template <class T> struct equal_to;
+  template <class T> struct not_equal_to;
+  template <class T> struct greater;
+  template <class T> struct less;
+  template <class T> struct greater_equal;
+  template <class T> struct less_equal;
+ 
+  // logical operations:
+  template <class T> struct logical_and;
+  template <class T> struct logical_or;
+  template <class T> struct logical_not;
+ 
+  // bitwise operations:
+  template <class T> struct bit_and;
+  template <class T> struct bit_or;
+  template <class T> struct bit_xor;
+ 
+  // negators:
+  template <class Predicate> class unary_negate;
+  template <class Predicate>  class binary_negate;
+ 
+  // bind:
+  template<class T> struct is_bind_expression;
+  template<class T> struct is_placeholder;
+
+  namespace placeholders {
+    // M is the implementation-defined number of placeholders
+    // (8 should be enough for interrogate)
+    extern char _1;
+    extern char _2;
+    extern char _3;
+    extern char _4;
+    extern char _5;
+    extern char _6;
+    extern char _7;
+    extern char _8;
+  }
+ 
+  // binders (deprecated):
+  template <class Fn> class binder1st;
+  template <class Fn> class binder2nd;
+
+  // adaptors (deprecated):
+  template <class Arg, class Result> class pointer_to_unary_function;
+  template <class Arg1, class Arg2, class Result>
+    class pointer_to_binary_function;
+ 
+  // adaptors (deprecated):
+  template<class S, class T> class mem_fun_t;
+  template<class S, class T, class A> class mem_fun1_t;
+  template<class S, class T> class mem_fun_ref_t;
+  template<class S, class T, class A> class mem_fun1_ref_t;
+  template <class S, class T> class const_mem_fun_t;
+  template <class S, class T, class A> class const_mem_fun1_t;
+  template <class S, class T> class const_mem_fun_ref_t;
+  template <class S, class T, class A> class const_mem_fun1_ref_t;
+ 
+
+  // polymorphic function wrappers:
+  class bad_function_call;
+
+  // hash function base template:
+  template <class T> struct hash;
+ 
+  // Hash function specializations
+  template <> struct hash<bool>;
+  template <> struct hash<char>;
+  template <> struct hash<signed char>;
+  template <> struct hash<unsigned char>;
+  template <> struct hash<char16_t>;
+  template <> struct hash<char32_t>;
+  template <> struct hash<wchar_t>;
+  template <> struct hash<short>;
+  template <> struct hash<unsigned short>;
+  template <> struct hash<int>;
+  template <> struct hash<unsigned int>;
+  template <> struct hash<long>;
+  template <> struct hash<long long>;
+  template <> struct hash<unsigned long>;
+  template <> struct hash<unsigned long long>;
+  template <> struct hash<float>;
+  template <> struct hash<double>;
+  template <> struct hash<long double>;
+  template<class T> struct hash<T*>;
+   
+  template <class T> class reference_wrapper {
+  public :
+    // types
+    typedef T type;
+    typedef void   result_type;      // not always defined
+    typedef void argument_type;    // not always defined
+    typedef void  first_argument_type;  // not always defined
+    typedef void  second_argument_type; // not always defined
+  };
+
+  template<class T> struct is_bind_expression {};
+  // : integral_constant<bool, true> {};
+
+  class bad_function_call : public std::exception {};
+
+  // template<class> class function; // undefined
+   
+  template< class R, class... ArgTypes >
+  class function {
+  public:
+    typedef R result_type;
+  };
+
+}
+
+
+#endif

+ 34 - 0
dtool/src/parser-inc/initializer_list

@@ -0,0 +1,34 @@
+/**
+ * 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 initializer_list
+ * @author tobspr
+ * @date 2016-11-01
+ */
+
+// This file, and all the other files in this directory, aren't
+// intended to be compiled--they're just parsed by CPPParser (and
+// interrogate) in lieu of the actual system headers, to generate the
+// interrogate database.
+
+#ifndef INITIALIZER_LIST_H
+#define INITIALIZER_LIST_H
+
+#include <stdtypedefs.h>
+
+namespace std {
+  template<class E> class initializer_list {
+  public:
+    typedef E value_type;
+    typedef const E& reference;
+    typedef const E& const_reference;
+    typedef size_t size_type;
+    typedef const E* iterator;
+    typedef const E* const_iterator;
+  };
+}

+ 163 - 23
dtool/src/parser-inc/memory

@@ -1,16 +1,15 @@
-// Filename: allocator
-// Created by:  drose (12May00)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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."
-//
-////////////////////////////////////////////////////////////////////
+/**
+ * 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 memory
+ * @author tobspr
+ * @date 2016-11-01
+ */
 
 
 // This file, and all the other files in this directory, aren't
 // This file, and all the other files in this directory, aren't
 // intended to be compiled--they're just parsed by CPPParser (and
 // intended to be compiled--they're just parsed by CPPParser (and
@@ -21,6 +20,8 @@
 #define ALLOCATOR_H
 #define ALLOCATOR_H
 
 
 #include <stdtypedefs.h>
 #include <stdtypedefs.h>
+#include <iterator>
+
 
 
 #ifdef GCC_STYLE_ALLOCATOR
 #ifdef GCC_STYLE_ALLOCATOR
 
 
@@ -33,16 +34,155 @@ public:
 #else  // GCC_STYLE_ALLOCATOR
 #else  // GCC_STYLE_ALLOCATOR
 
 
 namespace std {
 namespace std {
-  template<class Type>
-  class allocator {
-  public:
-    typedef Type *pointer;
-    typedef const Type *const_pointer;
-    typedef size_t size_type;
-
-    pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
-    void deallocate(pointer p, size_type n);
-  };
+
+    // pointer traits
+    template <class Ptr> struct pointer_traits;
+    template <class T> struct pointer_traits<T*>;
+ 
+    // pointer safety
+    enum class pointer_safety { relaxed, preferred, strict };
+    
+    // allocator argument tag
+    struct allocator_arg_t { };
+    constexpr allocator_arg_t allocator_arg = allocator_arg_t();
+ 
+    // uses_allocator
+    template <class T, class Alloc> struct uses_allocator;
+ 
+    // allocator traits
+    template <class Alloc> struct allocator_traits;
+ 
+    // the default allocator:
+    template <class T> class allocator;
+    template <> class allocator<void>;
+    
+    // raw storage iterator:
+    template <class OutputIterator, class T> class raw_storage_iterator;
+ 
+    // class template unique_ptr:
+    template <class T> class default_delete;
+    template <class T> class default_delete<T[]>;
+    template <class T, class D = default_delete<T>> class unique_ptr;
+    template <class T, class D> class unique_ptr<T[], D>;
+    // class bad_weak_ptr:
+    class bad_weak_ptr;
+ 
+    // class template shared_ptr:
+    template<class T> class shared_ptr;
+    // class template weak_ptr:
+    template<class T> class weak_ptr;
+ 
+    // class template owner_less:
+    template<class T> class owner_less;
+ 
+    // class template enable_shared_from_this:
+    template<class T> class enable_shared_from_this;
+ 
+    //  hash support
+    template <class T> struct hash;
+    template <class T, class D> struct hash<unique_ptr<T, D> >;
+    template <class T> struct hash<shared_ptr<T> >;
+ 
+    // auto_ptr (deprecated)
+    template <class X> class auto_ptr;
+
+    template <class Ptr> struct pointer_traits {
+        typedef Ptr         pointer;
+        typedef Ptr         element_type;
+        typedef ptrdiff_t   difference_type;
+ 
+        template <class U> using rebind = U; 
+    };
+
+    template <class T> struct pointer_traits<T*> {
+        typedef T*          pointer;
+        typedef T           element_type;
+        typedef ptrdiff_t   difference_type;
+ 
+        template <class U> using rebind = U*;
+    };
+
+
+    template <class Alloc> struct allocator_traits {
+        typedef Alloc allocator_type;
+ 
+        typedef typename Alloc::value_type value_type;
+ 
+        typedef void* pointer;
+        typedef const void* const_pointer;
+        typedef void* void_pointer;
+        typedef const void* const_void_pointer;
+ 
+        typedef std::ptrdiff_t difference_type;
+        typedef size_t size_type;
+ 
+        struct propagate_on_container_copy_assignment;
+        struct propagate_on_container_move_assignment;
+        struct propagate_on_container_swap;
+        struct is_always_equal;
+ 
+        template <class T> using rebind_alloc = size_t;
+        template <class T> using rebind_traits = allocator_traits<rebind_alloc<T> >;
+    };
+
+    template <class T> class allocator;
+    // specialize for void:
+    template <> class allocator<void> {
+    public:
+        typedef void*           pointer;
+        typedef const void*     const_pointer;
+        // reference-to-void members are impossible.
+        typedef void            value_type;
+        template <class U> struct rebind { typedef allocator<U> other; };
+    };
+    template <class T> class allocator {
+    public:
+        struct true_type_; // do not depend on type_traits header
+        typedef size_t          size_type;
+        typedef ptrdiff_t       difference_type;
+        typedef T*              pointer;
+        typedef const T*        const_pointer;
+        typedef T&              reference;
+        typedef const T&        const_reference;
+        typedef T               value_type;
+        template <class U> struct rebind { typedef allocator<U> other; };
+        typedef true_type_       propagate_on_container_move_assignment;
+        typedef true_type_       is_always_equal;
+ 
+    };
+
+    template <class OutputIterator, class T>
+    class raw_storage_iterator
+        : public iterator<output_iterator_tag,void,void,void,void> {
+    public:
+    };
+
+
+    template <class T> struct default_delete {};
+ 
+    template <class T> struct default_delete<T[]> {};
+
+    //  unique_ptr for single objects
+    template <class T, class D = default_delete<T>> class unique_ptr {
+    public:
+        typedef T* pointer;
+        typedef T  element_type;
+        typedef D  deleter_type;
+    };
+ 
+    class bad_weak_ptr: public std::exception {};
+
+    template<class T> class shared_ptr {
+    public:
+        typedef T element_type;
+    };
+
+    template<class T> class weak_ptr {
+    public:
+        typedef T element_type;
+    };
+
+    template<class T> class enable_shared_from_this {};
 }
 }
 
 
 #endif  // GCC_STYLE_ALLOCATOR
 #endif  // GCC_STYLE_ALLOCATOR

+ 34 - 14
dtool/src/parser-inc/stdint.h

@@ -20,25 +20,45 @@
 #define __WORDSIZE 32
 #define __WORDSIZE 32
 #endif
 #endif
 
 
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
-typedef long long int int64_t;
+using intmax_t = long long int;
+using uintmax_t = unsigned long long int;
 
 
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long int uint64_t;
+using int8_t = signed char;
+using int16_t = short int;
+using int32_t = int;
+using int64_t = long long int;
 
 
-typedef long long int intmax_t;
-typedef unsigned long long int uintmax_t;
+using uint8_t = unsigned char;
+using uint16_t = unsigned short int;
+using uint32_t = unsigned int;
+using uint64_t = unsigned long long int;
+
+using int_least8_t = int8_t;
+using int_least16_t = int16_t;
+using int_least32_t = int32_t;
+using int_least64_t = int64_t;
+
+using uint_least8_t = uint8_t;
+using uint_least16_t = uint16_t;
+using uint_least32_t = uint32_t;
+using uint_least64_t = uint64_t;
+
+using int_fast8_t = int8_t;
+using int_fast16_t = int16_t;
+using int_fast32_t = int32_t;
+using int_fast64_t = int64_t;
+
+using uint_fast8_t = uint8_t;
+using uint_fast16_t = uint16_t;
+using uint_fast32_t = uint32_t;
+using uint_fast64_t = uint64_t;
 
 
 #if __WORDSIZE == 64
 #if __WORDSIZE == 64
-typedef int64_t intptr_t;
-typedef uint64_t uintptr_t;
+using intptr_t = int64_t;
+using uintptr_t = uint64_t;
 #else
 #else
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
+using intptr_t = int32_t;
+using uintptr_t = uint32_t;
 #endif
 #endif
 
 
 #endif
 #endif

+ 2 - 0
dtool/src/parser-inc/stdtypedefs.h

@@ -39,6 +39,8 @@ inline namespace std {
 #endif
 #endif
 }
 }
 
 
+struct timeval;
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 #define NULL 0L
 #define NULL 0L
 #else
 #else

+ 96 - 0
dtool/src/parser-inc/type_traits

@@ -0,0 +1,96 @@
+#pragma once
+
+#include <stdtypedefs.h>
+
+namespace std {
+  template<class T, T v>
+  struct integral_constant {
+    static constexpr T value = v;
+    typedef T value_type;
+    constexpr operator value_type() const noexcept { return value; }
+    constexpr value_type operator()() const noexcept { return value; }
+  };
+
+  typedef integral_constant<bool, true> true_type;
+  typedef integral_constant<bool, false> false_type;
+
+  template<class T, class U>
+  struct is_same : std::false_type {};
+
+  template<class T>
+  struct is_same<T, T> : std::true_type {};
+
+  template<class T>
+  struct is_void : std::false_type {};
+
+  template<>
+  struct is_void<void> : std::true_type {};
+
+  template<class T>
+  struct is_enum : integral_constant<bool, __is_enum(T)> {};
+
+  template<class T>
+  struct is_union : integral_constant<bool, __is_union(T)> {};
+
+  template<class T>
+  struct is_class : integral_constant<bool, __is_class(T)> {};
+
+  template<class T>
+  struct is_fundamental : integral_constant<bool, __is_fundamental(T)> {};
+
+  template<class T>
+  struct is_compound : integral_constant<bool, !__is_fundamental(T)> {};
+
+  template<class T>
+  struct is_trivial : integral_constant<bool, __is_trivial(T)> {};
+
+  template<class T>
+  struct is_standard_layout : integral_constant<bool, __is_standard_layout(T)> {};
+
+  template<class T>
+  struct is_pod : integral_constant<bool, __is_pod(T)> {};
+
+  template<class T>
+  struct is_empty : integral_constant<bool, __is_empty(T)> {};
+
+  template<class T>
+  struct is_polymorphic : integral_constant<bool, __is_polymorphic(T)> {};
+
+  template<class T>
+  struct is_abstract : integral_constant<bool, __is_abstract(T)> {};
+
+  template<class T>
+  struct is_final : integral_constant<bool, __is_final(T)> {};
+
+  template<class T>
+  struct is_default_constructible : integral_constant<bool, __is_constructible(T)> {};
+
+  template<class T>
+  struct is_copy_constructible : integral_constant<bool, __is_constructible(T, const T&)> {};
+
+  template<class T>
+  struct is_move_constructible : integral_constant<bool, __is_constructible(T, const T&&)> {};
+
+  template<class T>
+  struct is_destructible : integral_constant<bool, __is_destructible(T)> {};
+
+  template<class T>
+  struct has_virtual_destructor : integral_constant<bool, __has_virtual_destructor(T)> {};
+
+  template<class T >
+  struct alignment_of : std::integral_constant<std::size_t, alignof(T)> {};
+
+  template<class T, class U>
+  struct is_base_of : integral_constant<bool, __is_base_of(T, U)> {};
+
+  template<class T, class U>
+  struct is_convertible : integral_constant<bool, __is_convertible_to(T, U)> {};
+
+  template<class T> struct add_cv { typedef const volatile T type; };
+  template<class T> struct add_const { typedef const T type; };
+  template<class T> struct add_volatile { typedef volatile T type; };
+
+  template<class T> struct add_lvalue_reference { typedef T &type; };
+  template<class T> struct add_rvalue_reference { typedef T &&type; };
+  template<class T> struct add_pointer { typedef T *type; };
+}

+ 84 - 0
dtool/src/parser-inc/unordered_map

@@ -0,0 +1,84 @@
+/**
+ * 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 unordered_map
+ * @author tobspr
+ * @date 2016-11-01
+ */
+
+// This file, and all the other files in this directory, aren't
+// intended to be compiled--they're just parsed by CPPParser (and
+// interrogate) in lieu of the actual system headers, to generate the
+// interrogate database.
+
+#ifndef UNORDERED_MAP_H
+#define UNORDERED_MAP_H
+
+#include <stdtypedefs.h>
+#include <stdcompare.h>
+#include <pair>
+#include <initializer_list>
+#include <functional>
+
+namespace std {
+ 
+  template <class Key,
+    class T,
+    class Hash = hash<Key>,
+    class Pred = std::equal_to<Key>,
+    class Allocator = std::allocator<std::pair<const Key, T> > >
+  class unordered_map
+  {
+  public:
+    // types
+    typedef Key key_type;
+    typedef Key value_type;
+    typedef Hash hasher;
+    typedef Pred key_equal;
+    typedef Allocator allocator_type;
+    typedef typename allocator_type::pointer pointer;
+    typedef typename allocator_type::const_pointer const_pointer;
+    typedef typename allocator_type::reference reference;
+    typedef typename allocator_type::const_reference const_reference;
+    typedef size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+    class iterator;
+    class const_iterator;
+    class local_iterator;
+    class const_local_iterator;
+  };
+
+  template <class Key,
+  class T,
+  class Hash = hash<Key>,
+  class Pred = std::equal_to<Key>,
+  class Allocator = std::allocator<std::pair<const Key, T> > >
+  class unordered_multimap
+  {
+  public:
+    // types
+    typedef Key key_type;
+    typedef Key value_type;
+    typedef Hash hasher;
+    typedef Pred key_equal;
+    typedef Allocator allocator_type;
+    typedef typename allocator_type::pointer pointer;
+    typedef typename allocator_type::const_pointer const_pointer;
+    typedef typename allocator_type::reference reference;
+    typedef typename allocator_type::const_reference const_reference;
+    typedef size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+    class iterator;
+    class const_iterator;
+    class local_iterator;
+    class const_local_iterator;
+  };
+
+} // namespace std
+
+#endif

+ 83 - 0
dtool/src/parser-inc/unordered_set

@@ -0,0 +1,83 @@
+/**
+ * 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 unordered_set
+ * @author tobspr
+ * @date 2016-11-01
+ */
+
+// This file, and all the other files in this directory, aren't
+// intended to be compiled--they're just parsed by CPPParser (and
+// interrogate) in lieu of the actual system headers, to generate the
+// interrogate database.
+
+#ifndef UNORDERED_SET_H
+#define UNORDERED_SET_H
+
+#include <stdtypedefs.h>
+#include <stdcompare.h>
+#include <pair>
+#include <initializer_list>
+#include <functional>
+
+namespace std {
+
+  template <class Key,
+    class Hash = hash<Key>,
+    class Pred = std::equal_to<Key>,
+    class Allocator = std::allocator<Key> >
+  class unordered_set
+  {
+  public:
+    // types
+    typedef Key key_type;
+    typedef Key value_type;
+    typedef Hash hasher;
+    typedef Pred key_equal;
+    typedef Allocator allocator_type;
+    typedef typename allocator_type::pointer pointer;
+    typedef typename allocator_type::const_pointer const_pointer;
+    typedef typename allocator_type::reference reference;
+    typedef typename allocator_type::const_reference  const_reference;
+    typedef size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+   
+    class iterator;
+    class const_iterator;
+    class local_iterator;
+    class const_local_iterator;
+  };
+
+  template <class Key,
+    class Hash = hash<Key>,
+    class Pred = std::equal_to<Key>,
+    class Allocator = std::allocator<Key> >
+  class unordered_multiset
+  {
+  public:
+    // types
+    typedef Key key_type;
+    typedef Key value_type;
+    typedef Hash hasher;
+    typedef Pred key_equal;
+    typedef Allocator allocator_type;
+    typedef typename allocator_type::pointer pointer;
+    typedef typename allocator_type::const_pointer    const_pointer;
+    typedef typename allocator_type::reference reference;
+    typedef typename allocator_type::const_reference  const_reference;
+    typedef size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+    class iterator;
+    class const_iterator;
+    class local_iterator;
+    class const_local_iterator;
+  };
+
+} // namespace std
+
+#endif

+ 1 - 0
dtool/src/parser-inc/xmmintrin.h

@@ -0,0 +1 @@
+struct __m128;

+ 0 - 1
dtool/src/prc/.gitignore

@@ -1 +0,0 @@
-/prc_parameters.h

+ 42 - 33
dtool/src/prc/encryptStreamBuf.cxx

@@ -73,8 +73,8 @@ EncryptStreamBuf() {
   _key_length = encryption_key_length;
   _key_length = encryption_key_length;
   _iteration_count = encryption_iteration_count;
   _iteration_count = encryption_iteration_count;
 
 
-  _read_valid = false;
-  _write_valid = false;
+  _read_ctx = NULL;
+  _write_ctx = NULL;
 
 
   _read_overflow_buffer = NULL;
   _read_overflow_buffer = NULL;
   _in_read_overflow_buffer = 0;
   _in_read_overflow_buffer = 0;
@@ -110,7 +110,11 @@ open_read(istream *source, bool owns_source, const string &password) {
 
 
   _source = source;
   _source = source;
   _owns_source = owns_source;
   _owns_source = owns_source;
-  _read_valid = false;
+
+  if (_read_ctx != NULL) {
+    EVP_CIPHER_CTX_free(_read_ctx);
+    _read_ctx = NULL;
+  }
 
 
   // Now read the header information.
   // Now read the header information.
   StreamReader sr(_source, false);
   StreamReader sr(_source, false);
@@ -143,17 +147,21 @@ open_read(istream *source, bool owns_source, const string &password) {
 
 
   string iv = sr.extract_bytes(iv_length);
   string iv = sr.extract_bytes(iv_length);
 
 
+  _read_ctx = EVP_CIPHER_CTX_new();
+  nassertv(_read_ctx != NULL);
+
   // Initialize the context
   // Initialize the context
   int result;
   int result;
-  result = EVP_DecryptInit(&_read_ctx, cipher, NULL, (unsigned char *)iv.data());
+  result = EVP_DecryptInit(_read_ctx, cipher, NULL, (unsigned char *)iv.data());
   nassertv(result > 0);
   nassertv(result > 0);
 
 
-  result = EVP_CIPHER_CTX_set_key_length(&_read_ctx, key_length);
+  result = EVP_CIPHER_CTX_set_key_length(_read_ctx, key_length);
   if (result <= 0) {
   if (result <= 0) {
     prc_cat.error()
     prc_cat.error()
       << "Invalid key length " << key_length * 8 << " bits for algorithm "
       << "Invalid key length " << key_length * 8 << " bits for algorithm "
       << OBJ_nid2sn(nid) << "\n";
       << OBJ_nid2sn(nid) << "\n";
-    EVP_CIPHER_CTX_cleanup(&_read_ctx);
+    EVP_CIPHER_CTX_free(_read_ctx);
+    _read_ctx = NULL;
     return;
     return;
   }
   }
 
 
@@ -167,11 +175,9 @@ open_read(istream *source, bool owns_source, const string &password) {
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   // Store the key within the context.
   // Store the key within the context.
-  result = EVP_DecryptInit(&_read_ctx, NULL, key, NULL);
+  result = EVP_DecryptInit(_read_ctx, NULL, key, NULL);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
-  _read_valid = true;
-
   _read_overflow_buffer = new unsigned char[_read_block_size];
   _read_overflow_buffer = new unsigned char[_read_block_size];
   _in_read_overflow_buffer = 0;
   _in_read_overflow_buffer = 0;
   thread_consider_yield();
   thread_consider_yield();
@@ -182,9 +188,9 @@ open_read(istream *source, bool owns_source, const string &password) {
  */
  */
 void EncryptStreamBuf::
 void EncryptStreamBuf::
 close_read() {
 close_read() {
-  if (_read_valid) {
-    EVP_CIPHER_CTX_cleanup(&_read_ctx);
-    _read_valid = false;
+  if (_read_ctx != NULL) {
+    EVP_CIPHER_CTX_free(_read_ctx);
+    _read_ctx = NULL;
   }
   }
 
 
   if (_read_overflow_buffer != (unsigned char *)NULL) {
   if (_read_overflow_buffer != (unsigned char *)NULL) {
@@ -211,7 +217,6 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   close_write();
   close_write();
   _dest = dest;
   _dest = dest;
   _owns_dest = owns_dest;
   _owns_dest = owns_dest;
-  _write_valid = false;
 
 
   const EVP_CIPHER *cipher =
   const EVP_CIPHER *cipher =
     EVP_get_cipherbyname(_algorithm.c_str());
     EVP_get_cipherbyname(_algorithm.c_str());
@@ -220,21 +225,23 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
     prc_cat.error()
     prc_cat.error()
       << "Unknown encryption algorithm: " << _algorithm << "\n";
       << "Unknown encryption algorithm: " << _algorithm << "\n";
     return;
     return;
-  };
+  }
 
 
   int nid = EVP_CIPHER_nid(cipher);
   int nid = EVP_CIPHER_nid(cipher);
 
 
   int iv_length = EVP_CIPHER_iv_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
   _write_block_size = EVP_CIPHER_block_size(cipher);
   _write_block_size = EVP_CIPHER_block_size(cipher);
 
 
-  unsigned char *iv = (unsigned char *)alloca(iv_length);
-
   // Generate a random IV.  It doesn't need to be cryptographically secure,
   // Generate a random IV.  It doesn't need to be cryptographically secure,
   // just unique.
   // just unique.
+  unsigned char *iv = (unsigned char *)alloca(iv_length);
   RAND_pseudo_bytes(iv, iv_length);
   RAND_pseudo_bytes(iv, iv_length);
 
 
+  _write_ctx = EVP_CIPHER_CTX_new();
+  nassertv(_write_ctx != NULL);
+
   int result;
   int result;
-  result = EVP_EncryptInit(&_write_ctx, cipher, NULL, iv);
+  result = EVP_EncryptInit(_write_ctx, cipher, NULL, iv);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   // Store the appropriate key length in the context.
   // Store the appropriate key length in the context.
@@ -242,12 +249,13 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   if (key_length == 0) {
   if (key_length == 0) {
     key_length = EVP_CIPHER_key_length(cipher);
     key_length = EVP_CIPHER_key_length(cipher);
   }
   }
-  result = EVP_CIPHER_CTX_set_key_length(&_write_ctx, key_length);
+  result = EVP_CIPHER_CTX_set_key_length(_write_ctx, key_length);
   if (result <= 0) {
   if (result <= 0) {
     prc_cat.error()
     prc_cat.error()
       << "Invalid key length " << key_length * 8 << " bits for algorithm "
       << "Invalid key length " << key_length * 8 << " bits for algorithm "
       << OBJ_nid2sn(nid) << "\n";
       << OBJ_nid2sn(nid) << "\n";
-    EVP_CIPHER_CTX_cleanup(&_write_ctx);
+    EVP_CIPHER_CTX_free(_write_ctx);
+    _write_ctx = NULL;
     return;
     return;
   }
   }
 
 
@@ -271,7 +279,7 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   // Store the key in the context.
   // Store the key in the context.
-  result = EVP_EncryptInit(&_write_ctx, NULL, key, NULL);
+  result = EVP_EncryptInit(_write_ctx, NULL, key, NULL);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   // Now write the header information to the stream.
   // Now write the header information to the stream.
@@ -284,7 +292,6 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   sw.add_uint16((uint16_t)count);
   sw.add_uint16((uint16_t)count);
   sw.append_data(iv, iv_length);
   sw.append_data(iv, iv_length);
 
 
-  _write_valid = true;
   thread_consider_yield();
   thread_consider_yield();
 }
 }
 
 
@@ -298,15 +305,16 @@ close_write() {
     write_chars(pbase(), n);
     write_chars(pbase(), n);
     pbump(-(int)n);
     pbump(-(int)n);
 
 
-    if (_write_valid) {
+    if (_write_ctx != NULL) {
       unsigned char *write_buffer = (unsigned char *)alloca(_write_block_size);
       unsigned char *write_buffer = (unsigned char *)alloca(_write_block_size);
       int bytes_written = 0;
       int bytes_written = 0;
-      EVP_EncryptFinal(&_write_ctx, write_buffer, &bytes_written);
+      EVP_EncryptFinal(_write_ctx, write_buffer, &bytes_written);
       thread_consider_yield();
       thread_consider_yield();
 
 
       _dest->write((const char *)write_buffer, bytes_written);
       _dest->write((const char *)write_buffer, bytes_written);
 
 
-      _write_valid = false;
+      EVP_CIPHER_CTX_free(_write_ctx);
+      _write_ctx = NULL;
     }
     }
 
 
     if (_owns_dest) {
     if (_owns_dest) {
@@ -418,7 +426,7 @@ read_chars(char *start, size_t length) {
 
 
   do {
   do {
     // Get more bytes from the stream.
     // Get more bytes from the stream.
-    if (!_read_valid) {
+    if (_read_ctx == NULL) {
       return 0;
       return 0;
     }
     }
 
 
@@ -429,20 +437,21 @@ read_chars(char *start, size_t length) {
     int result;
     int result;
     if (source_length != 0) {
     if (source_length != 0) {
       result =
       result =
-        EVP_DecryptUpdate(&_read_ctx, read_buffer, &bytes_read,
+        EVP_DecryptUpdate(_read_ctx, read_buffer, &bytes_read,
                           source_buffer, source_length);
                           source_buffer, source_length);
     } else {
     } else {
       result =
       result =
-        EVP_DecryptFinal(&_read_ctx, read_buffer, &bytes_read);
-      _read_valid = false;
+        EVP_DecryptFinal(_read_ctx, read_buffer, &bytes_read);
+      EVP_CIPHER_CTX_free(_read_ctx);
+      _read_ctx = NULL;
     }
     }
 
 
     if (result <= 0) {
     if (result <= 0) {
       prc_cat.error()
       prc_cat.error()
         << "Error decrypting stream.\n";
         << "Error decrypting stream.\n";
-      if (_read_valid) {
-        EVP_CIPHER_CTX_cleanup(&_read_ctx);
-        _read_valid = false;
+      if (_read_ctx != NULL) {
+        EVP_CIPHER_CTX_free(_read_ctx);
+        _read_ctx = NULL;
       }
       }
     }
     }
     thread_consider_yield();
     thread_consider_yield();
@@ -472,13 +481,13 @@ read_chars(char *start, size_t length) {
  */
  */
 void EncryptStreamBuf::
 void EncryptStreamBuf::
 write_chars(const char *start, size_t length) {
 write_chars(const char *start, size_t length) {
-  if (_write_valid && length != 0) {
+  if (_write_ctx != NULL && length != 0) {
     size_t max_write_buffer = length + _write_block_size;
     size_t max_write_buffer = length + _write_block_size;
     unsigned char *write_buffer = (unsigned char *)alloca(max_write_buffer);
     unsigned char *write_buffer = (unsigned char *)alloca(max_write_buffer);
 
 
     int bytes_written = 0;
     int bytes_written = 0;
     int result =
     int result =
-      EVP_EncryptUpdate(&_write_ctx, write_buffer, &bytes_written,
+      EVP_EncryptUpdate(_write_ctx, write_buffer, &bytes_written,
                         (unsigned char *)start, length);
                         (unsigned char *)start, length);
     if (result <= 0) {
     if (result <= 0) {
       prc_cat.error()
       prc_cat.error()

+ 2 - 4
dtool/src/prc/encryptStreamBuf.h

@@ -64,14 +64,12 @@ private:
   int _key_length;
   int _key_length;
   int _iteration_count;
   int _iteration_count;
 
 
-  bool _read_valid;
-  EVP_CIPHER_CTX _read_ctx;
+  EVP_CIPHER_CTX *_read_ctx;
   size_t _read_block_size;
   size_t _read_block_size;
   unsigned char *_read_overflow_buffer;
   unsigned char *_read_overflow_buffer;
   size_t _in_read_overflow_buffer;
   size_t _in_read_overflow_buffer;
 
 
-  bool _write_valid;
-  EVP_CIPHER_CTX _write_ctx;
+  EVP_CIPHER_CTX *_write_ctx;
   size_t _write_block_size;
   size_t _write_block_size;
 };
 };
 
 

+ 3 - 0
dtool/src/prc/notify.cxx

@@ -343,6 +343,9 @@ assert_failure(const char *expression, int line,
   // guarantee it has already been constructed.
   // guarantee it has already been constructed.
   ALIGN_16BYTE ConfigVariableBool assert_abort("assert-abort", false);
   ALIGN_16BYTE ConfigVariableBool assert_abort("assert-abort", false);
   if (assert_abort) {
   if (assert_abort) {
+    // Make sure the error message has been flushed to the output.
+    nout.flush();
+
 #ifdef WIN32
 #ifdef WIN32
     // How to trigger an exception in VC++ that offers to take us into the
     // How to trigger an exception in VC++ that offers to take us into the
     // debugger?  abort() doesn't do it.  We used to be able to assert(false),
     // debugger?  abort() doesn't do it.  We used to be able to assert(false),

+ 4 - 0
dtool/src/pystub/pystub.cxx

@@ -149,12 +149,14 @@ extern "C" {
   EXPCL_PYSTUB int PyUnicodeUCS2_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_AsWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_AsWideChar(...);
+  EXPCL_PYSTUB int PyUnicodeUCS2_AsWideCharString(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_GetSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS2_GetSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromFormat(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromFormat(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromString(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromString(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_FromWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_AsWideChar(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_AsWideChar(...);
+  EXPCL_PYSTUB int PyUnicodeUCS4_AsWideCharString(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_GetSize(...);
   EXPCL_PYSTUB int PyUnicodeUCS4_GetSize(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
@@ -349,12 +351,14 @@ int PyUnicodeUCS2_FromString(...) { return 0; }
 int PyUnicodeUCS2_FromStringAndSize(...) { return 0; }
 int PyUnicodeUCS2_FromStringAndSize(...) { return 0; }
 int PyUnicodeUCS2_FromWideChar(...) { return 0; }
 int PyUnicodeUCS2_FromWideChar(...) { return 0; }
 int PyUnicodeUCS2_AsWideChar(...) { return 0; }
 int PyUnicodeUCS2_AsWideChar(...) { return 0; }
+int PyUnicodeUCS2_AsWideCharString(...) { return 0; }
 int PyUnicodeUCS2_GetSize(...) { return 0; }
 int PyUnicodeUCS2_GetSize(...) { return 0; }
 int PyUnicodeUCS4_FromFormat(...) { return 0; }
 int PyUnicodeUCS4_FromFormat(...) { return 0; }
 int PyUnicodeUCS4_FromString(...) { return 0; }
 int PyUnicodeUCS4_FromString(...) { return 0; }
 int PyUnicodeUCS4_FromStringAndSize(...) { return 0; }
 int PyUnicodeUCS4_FromStringAndSize(...) { return 0; }
 int PyUnicodeUCS4_FromWideChar(...) { return 0; }
 int PyUnicodeUCS4_FromWideChar(...) { return 0; }
 int PyUnicodeUCS4_AsWideChar(...) { return 0; }
 int PyUnicodeUCS4_AsWideChar(...) { return 0; }
+int PyUnicodeUCS4_AsWideCharString(...) { return 0; }
 int PyUnicodeUCS4_GetSize(...) { return 0; }
 int PyUnicodeUCS4_GetSize(...) { return 0; }
 int PyUnicode_AsUTF8(...) { return 0; }
 int PyUnicode_AsUTF8(...) { return 0; }
 int PyUnicode_AsUTF8AndSize(...) { return 0; }
 int PyUnicode_AsUTF8AndSize(...) { return 0; }

+ 0 - 2
makepanda/.gitignore

@@ -1,2 +0,0 @@
-*.pyc
-*.pyo

+ 29 - 3
makepanda/installer.nsi

@@ -31,6 +31,7 @@ SetCompressor ${COMPRESSOR}
 !include "Sections.nsh"
 !include "Sections.nsh"
 !include "WinMessages.nsh"
 !include "WinMessages.nsh"
 !include "WordFunc.nsh"
 !include "WordFunc.nsh"
+!include "x64.nsh"
 
 
 !define MUI_WELCOMEFINISHPAGE_BITMAP "panda-install.bmp"
 !define MUI_WELCOMEFINISHPAGE_BITMAP "panda-install.bmp"
 !define MUI_UNWELCOMEFINISHPAGE_BITMAP "panda-install.bmp"
 !define MUI_UNWELCOMEFINISHPAGE_BITMAP "panda-install.bmp"
@@ -120,6 +121,14 @@ Function runFunction
     ExecShell "open" "$SMPROGRAMS\${TITLE}\Panda3D Manual.lnk"
     ExecShell "open" "$SMPROGRAMS\${TITLE}\Panda3D Manual.lnk"
 FunctionEnd
 FunctionEnd
 
 
+Function .onInit
+    ${If} ${REGVIEW} = 64
+    ${AndIfNot} ${RunningX64}
+        MessageBox MB_OK|MB_ICONEXCLAMATION "You are attempting to install the 64-bit version of Panda3D on a 32-bit version of Windows.  Please download and install the 32-bit version of Panda3D instead."
+        Abort
+    ${EndIf}
+FunctionEnd
+
 SectionGroup "Panda3D Libraries"
 SectionGroup "Panda3D Libraries"
     Section "Core Libraries" SecCore
     Section "Core Libraries" SecCore
         SectionIn 1 2 RO
         SectionIn 1 2 RO
@@ -134,12 +143,22 @@ SectionGroup "Panda3D Libraries"
         SetOutPath "$INSTDIR"
         SetOutPath "$INSTDIR"
         File "${BUILT}\LICENSE"
         File "${BUILT}\LICENSE"
         File /r /x CVS "${BUILT}\ReleaseNotes"
         File /r /x CVS "${BUILT}\ReleaseNotes"
-        SetOutPath $INSTDIR\bin
-        File /r /x libpandagl.dll /x libpandadx9.dll /x cgD3D*.dll /x python*.dll /x libpandaode.dll /x libp3fmod_audio.dll /x fmodex*.dll /x libp3ffmpeg.dll /x av*.dll /x postproc*.dll /x swscale*.dll /x swresample*.dll /x NxCharacter*.dll /x cudart*.dll /x PhysX*.dll /x libpandaphysx.dll /x libp3rocket.dll /x boost_python*.dll /x Rocket*.dll /x _rocket*.pyd /x libpandabullet.dll /x OpenAL32.dll /x *_oal.dll /x libp3openal_audio.dll "${BUILT}\bin\*.dll"
-        File /nonfatal /r "${BUILT}\bin\Microsoft.*.manifest"
+
         SetOutPath $INSTDIR\etc
         SetOutPath $INSTDIR\etc
         File /r "${BUILT}\etc\*"
         File /r "${BUILT}\etc\*"
 
 
+        SetOutPath $INSTDIR\bin
+        File /r /x api-ms-win-*.dll /x ucrtbase.dll /x libpandagl.dll /x libpandadx9.dll /x cgD3D*.dll /x python*.dll /x libpandaode.dll /x libp3fmod_audio.dll /x fmodex*.dll /x libp3ffmpeg.dll /x av*.dll /x postproc*.dll /x swscale*.dll /x swresample*.dll /x NxCharacter*.dll /x cudart*.dll /x PhysX*.dll /x libpandaphysx.dll /x libp3rocket.dll /x boost_python*.dll /x Rocket*.dll /x _rocket*.pyd /x libpandabullet.dll /x OpenAL32.dll /x *_oal.dll /x libp3openal_audio.dll "${BUILT}\bin\*.dll"
+        File /nonfatal /r "${BUILT}\bin\Microsoft.*.manifest"
+
+        ; Before Windows 10, we need these stubs for the UCRT as well.
+        ReadRegDWORD $0 HKLM "Software\Microsoft\Windows NT\CurrentVersion" "CurrentMajorVersionNumber"
+        ${If} $0 < 10
+            ClearErrors
+            File /nonfatal /r "${BUILT}\bin\api-ms-win-*.dll"
+            File /nonfatal "${BUILT}\bin\ucrtbase.dll"
+        ${Endif}
+
         SetDetailsPrint both
         SetDetailsPrint both
         DetailPrint "Installing models..."
         DetailPrint "Installing models..."
         SetDetailsPrint listonly
         SetDetailsPrint listonly
@@ -147,6 +166,10 @@ SectionGroup "Panda3D Libraries"
         SetOutPath $INSTDIR\models
         SetOutPath $INSTDIR\models
         File /r /x CVS "${BUILT}\models\*"
         File /r /x CVS "${BUILT}\models\*"
 
 
+        SetDetailsPrint both
+        DetailPrint "Installing optional components..."
+        SetDetailsPrint listonly
+
         RMDir /r "$SMPROGRAMS\${TITLE}"
         RMDir /r "$SMPROGRAMS\${TITLE}"
         CreateDirectory "$SMPROGRAMS\${TITLE}"
         CreateDirectory "$SMPROGRAMS\${TITLE}"
     SectionEnd
     SectionEnd
@@ -634,6 +657,9 @@ Section -post
     WriteRegStr HKCU "Software\Classes\.pz" "PerceivedType" "compressed"
     WriteRegStr HKCU "Software\Classes\.pz" "PerceivedType" "compressed"
     WriteRegStr HKCU "Software\Classes\.mf" "" "Panda3D.Multifile"
     WriteRegStr HKCU "Software\Classes\.mf" "" "Panda3D.Multifile"
     WriteRegStr HKCU "Software\Classes\.mf" "PerceivedType" "compressed"
     WriteRegStr HKCU "Software\Classes\.mf" "PerceivedType" "compressed"
+    WriteRegStr HKCU "Software\Classes\.prc" "" "inifile"
+    WriteRegStr HKCU "Software\Classes\.prc" "Content Type" "text/plain"
+    WriteRegStr HKCU "Software\Classes\.prc" "PerceivedType" "text"
 
 
     ; For convenience, if nobody registered .pyd, we will.
     ; For convenience, if nobody registered .pyd, we will.
     ReadRegStr $0 HKCR "Software\Classes\.pyd" ""
     ReadRegStr $0 HKCR "Software\Classes\.pyd" ""

+ 196 - 115
makepanda/makepanda.py

@@ -39,6 +39,7 @@ import sys
 
 
 COMPILER=0
 COMPILER=0
 INSTALLER=0
 INSTALLER=0
+WHEEL=0
 GENMAN=0
 GENMAN=0
 COMPRESSOR="zlib"
 COMPRESSOR="zlib"
 THREADCOUNT=0
 THREADCOUNT=0
@@ -51,6 +52,7 @@ RUNTIME=0
 DISTRIBUTOR=""
 DISTRIBUTOR=""
 VERSION=None
 VERSION=None
 DEBVERSION=None
 DEBVERSION=None
+WHLVERSION=None
 RPMRELEASE="1"
 RPMRELEASE="1"
 GIT_COMMIT=None
 GIT_COMMIT=None
 P3DSUFFIX=None
 P3DSUFFIX=None
@@ -87,14 +89,13 @@ PkgListSet(["PYTHON", "DIRECT",                        # Python support
   "MFC", "WX", "FLTK",                                 # Used for web plug-in only
   "MFC", "WX", "FLTK",                                 # Used for web plug-in only
   "ROCKET", "AWESOMIUM",                               # GUI libraries
   "ROCKET", "AWESOMIUM",                               # GUI libraries
   "CARBON", "COCOA",                                   # Mac OS X toolkits
   "CARBON", "COCOA",                                   # Mac OS X toolkits
-  "X11", "XF86DGA", "XRANDR", "XCURSOR",               # Unix platform support
-  "PANDATOOL", "PVIEW", "DEPLOYTOOLS",                 # Toolchain
+  "X11",                                               # Unix platform support
+  "PANDATOOL", "PVIEW", "DEPLOYTOOLS", "DIRECTSCRIPTS",# Toolchain
   "SKEL",                                              # Example SKEL project
   "SKEL",                                              # Example SKEL project
   "PANDAFX",                                           # Some distortion special lenses
   "PANDAFX",                                           # Some distortion special lenses
   "PANDAPARTICLESYSTEM",                               # Built in particle system
   "PANDAPARTICLESYSTEM",                               # Built in particle system
   "CONTRIB",                                           # Experimental
   "CONTRIB",                                           # Experimental
   "SSE2", "NEON",                                      # Compiler features
   "SSE2", "NEON",                                      # Compiler features
-  "TOUCHINPUT",                                        # Touchinput interface (requires Windows 7)
 ])
 ])
 
 
 CheckPandaSourceTree()
 CheckPandaSourceTree()
@@ -125,6 +126,7 @@ def usage(problem):
     print("  --verbose         (print out more information)")
     print("  --verbose         (print out more information)")
     print("  --runtime         (build a runtime build instead of an SDK build)")
     print("  --runtime         (build a runtime build instead of an SDK build)")
     print("  --installer       (build an installer)")
     print("  --installer       (build an installer)")
+    print("  --wheel           (build a pip-installable .whl)")
     print("  --optimize X      (optimization level can be 1,2,3,4)")
     print("  --optimize X      (optimization level can be 1,2,3,4)")
     print("  --version X       (set the panda version number)")
     print("  --version X       (set the panda version number)")
     print("  --lzma            (use lzma compression when building Windows installer)")
     print("  --lzma            (use lzma compression when building Windows installer)")
@@ -160,17 +162,18 @@ def usage(problem):
     os._exit(1)
     os._exit(1)
 
 
 def parseopts(args):
 def parseopts(args):
-    global INSTALLER,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION
+    global INSTALLER,WHEEL,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION
     global COMPRESSOR,THREADCOUNT,OSXTARGET,OSX_ARCHS,HOST_URL
     global COMPRESSOR,THREADCOUNT,OSXTARGET,OSX_ARCHS,HOST_URL
-    global DEBVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX,RTDIST_VERSION
+    global DEBVERSION,WHLVERSION,RPMRELEASE,GIT_COMMIT,P3DSUFFIX,RTDIST_VERSION
     global STRDXSDKVERSION, WINDOWS_SDK, MSVC_VERSION, BOOUSEINTELCOMPILER
     global STRDXSDKVERSION, WINDOWS_SDK, MSVC_VERSION, BOOUSEINTELCOMPILER
     longopts = [
     longopts = [
         "help","distributor=","verbose","runtime","osxtarget=",
         "help","distributor=","verbose","runtime","osxtarget=",
-        "optimize=","everything","nothing","installer","rtdist","nocolor",
+        "optimize=","everything","nothing","installer","wheel","rtdist","nocolor",
         "version=","lzma","no-python","threads=","outputdir=","override=",
         "version=","lzma","no-python","threads=","outputdir=","override=",
         "static","host=","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=",
         "static","host=","debversion=","rpmrelease=","p3dsuffix=","rtdist-version=",
         "directx-sdk=", "windows-sdk=", "msvc-version=", "clean", "use-icl",
         "directx-sdk=", "windows-sdk=", "msvc-version=", "clean", "use-icl",
-        "universal", "target=", "arch=", "git-commit="]
+        "universal", "target=", "arch=", "git-commit=",
+        "use-touchinput", "no-touchinput"]
     anything = 0
     anything = 0
     optimize = ""
     optimize = ""
     target = None
     target = None
@@ -188,6 +191,7 @@ def parseopts(args):
             if (option=="--help"): raise Exception
             if (option=="--help"): raise Exception
             elif (option=="--optimize"): optimize=value
             elif (option=="--optimize"): optimize=value
             elif (option=="--installer"): INSTALLER=1
             elif (option=="--installer"): INSTALLER=1
+            elif (option=="--wheel"): WHEEL=1
             elif (option=="--verbose"): SetVerbose(True)
             elif (option=="--verbose"): SetVerbose(True)
             elif (option=="--distributor"): DISTRIBUTOR=value
             elif (option=="--distributor"): DISTRIBUTOR=value
             elif (option=="--rtdist"): RTDIST=1
             elif (option=="--rtdist"): RTDIST=1
@@ -203,8 +207,11 @@ def parseopts(args):
             elif (option=="--arch"): target_arch = value.strip()
             elif (option=="--arch"): target_arch = value.strip()
             elif (option=="--nocolor"): DisableColors()
             elif (option=="--nocolor"): DisableColors()
             elif (option=="--version"):
             elif (option=="--version"):
-                VERSION=value
-                if (len(VERSION.split(".")) != 3): raise Exception
+                match = re.match(r'^\d+\.\d+\.\d+', value)
+                if not match:
+                    usage("version requires three digits")
+                WHLVERSION = value
+                VERSION = match.group()
             elif (option=="--lzma"): COMPRESSOR="lzma"
             elif (option=="--lzma"): COMPRESSOR="lzma"
             elif (option=="--override"): AddOverride(value.strip())
             elif (option=="--override"): AddOverride(value.strip())
             elif (option=="--static"): SetLinkAllStatic(True)
             elif (option=="--static"): SetLinkAllStatic(True)
@@ -316,18 +323,6 @@ def parseopts(args):
             print("No Windows SDK version specified. Defaulting to '7.1'.")
             print("No Windows SDK version specified. Defaulting to '7.1'.")
             WINDOWS_SDK = '7.1'
             WINDOWS_SDK = '7.1'
 
 
-        is_win7 = False
-        if sys.platform == 'win32':
-            # Note: not available in cygwin.
-            winver = sys.getwindowsversion()
-            if winver[0] >= 6 and winver[1] >= 1:
-                is_win7 = True
-
-        if RUNTIME or not is_win7:
-            PkgDisable("TOUCHINPUT")
-    else:
-        PkgDisable("TOUCHINPUT")
-
     if clean_build and os.path.isdir(GetOutputDir()):
     if clean_build and os.path.isdir(GetOutputDir()):
         print("Deleting %s" % (GetOutputDir()))
         print("Deleting %s" % (GetOutputDir()))
         shutil.rmtree(GetOutputDir())
         shutil.rmtree(GetOutputDir())
@@ -428,9 +423,18 @@ if (RUNTIME):
 if (INSTALLER and RTDIST):
 if (INSTALLER and RTDIST):
     exit("Cannot build an installer for the rtdist build!")
     exit("Cannot build an installer for the rtdist build!")
 
 
+if (WHEEL and RUNTIME):
+    exit("Cannot build a wheel for the runtime build!")
+
+if (WHEEL and RTDIST):
+    exit("Cannot build a wheel for the rtdist build!")
+
 if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME) and GetTarget() == 'windows':
 if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME) and GetTarget() == 'windows':
     exit("Cannot build installer on Windows without python")
     exit("Cannot build installer on Windows without python")
 
 
+if WHEEL and PkgSkip("PYTHON"):
+    exit("Cannot build wheel without Python")
+
 if (RTDIST) and (PkgSkip("WX") and PkgSkip("FLTK")):
 if (RTDIST) and (PkgSkip("WX") and PkgSkip("FLTK")):
     exit("Cannot build rtdist without wx or fltk")
     exit("Cannot build rtdist without wx or fltk")
 
 
@@ -516,9 +520,6 @@ IncDirectory("ALWAYS", GetOutputDir()+"/include")
 
 
 if (COMPILER == "MSVC"):
 if (COMPILER == "MSVC"):
     PkgDisable("X11")
     PkgDisable("X11")
-    PkgDisable("XRANDR")
-    PkgDisable("XF86DGA")
-    PkgDisable("XCURSOR")
     PkgDisable("GLES")
     PkgDisable("GLES")
     PkgDisable("GLES2")
     PkgDisable("GLES2")
     PkgDisable("EGL")
     PkgDisable("EGL")
@@ -808,9 +809,13 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("JPEG",      "",          ("jpeg"), "jpeglib.h")
         SmartPkgEnable("JPEG",      "",          ("jpeg"), "jpeglib.h")
         SmartPkgEnable("PNG",       "libpng",    ("png"), "png.h", tool = "libpng-config")
         SmartPkgEnable("PNG",       "libpng",    ("png"), "png.h", tool = "libpng-config")
 
 
-        if GetTarget() == "darwin" and not PkgSkip("FFMPEG"):
-            LibName("FFMPEG", "-Wl,-read_only_relocs,suppress")
-            LibName("FFMPEG", "-framework VideoDecodeAcceleration")
+        if not PkgSkip("FFMPEG"):
+            if GetTarget() == "darwin":
+                LibName("FFMPEG", "-Wl,-read_only_relocs,suppress")
+                LibName("FFMPEG", "-framework VideoDecodeAcceleration")
+            elif os.path.isfile(GetThirdpartyDir() + "ffmpeg/lib/libavcodec.a"):
+                # Needed when linking ffmpeg statically on Linux.
+                LibName("FFMPEG", "-Wl,-Bsymbolic")
 
 
         cv_lib = ChooseLib(("opencv_core", "cv"), "OPENCV")
         cv_lib = ChooseLib(("opencv_core", "cv"), "OPENCV")
         if cv_lib == "opencv_core":
         if cv_lib == "opencv_core":
@@ -840,12 +845,9 @@ if (COMPILER=="GCC"):
     if GetTarget() != 'darwin':
     if GetTarget() != 'darwin':
         # CgGL is covered by the Cg framework, and we don't need X11 components on OSX
         # CgGL is covered by the Cg framework, and we don't need X11 components on OSX
         if not PkgSkip("NVIDIACG") and not RUNTIME:
         if not PkgSkip("NVIDIACG") and not RUNTIME:
-            SmartPkgEnable("CGGL", "", ("CgGL"), "Cg/cgGL.h")
+            SmartPkgEnable("CGGL", "", ("CgGL"), "Cg/cgGL.h", thirdparty_dir = "nvidiacg")
         if not RUNTIME:
         if not RUNTIME:
             SmartPkgEnable("X11", "x11", "X11", ("X11", "X11/Xlib.h"))
             SmartPkgEnable("X11", "x11", "X11", ("X11", "X11/Xlib.h"))
-            SmartPkgEnable("XRANDR", "xrandr", "Xrandr", "X11/extensions/Xrandr.h")
-            SmartPkgEnable("XF86DGA", "xxf86dga", "Xxf86dga", "X11/extensions/xf86dga.h")
-            SmartPkgEnable("XCURSOR", "xcursor", "Xcursor", "X11/Xcursor/Xcursor.h")
 
 
     if GetHost() != "darwin":
     if GetHost() != "darwin":
         # Workaround for an issue where pkg-config does not include this path
         # Workaround for an issue where pkg-config does not include this path
@@ -1055,11 +1057,12 @@ def CompileCxx(obj,src,opts):
                 cmd += "/favor:blend "
                 cmd += "/favor:blend "
             cmd += "/wd4996 /wd4275 /wd4273 "
             cmd += "/wd4996 /wd4275 /wd4273 "
 
 
-            # Enable Windows 7 interfaces if we need Touchinput.
-            if PkgSkip("TOUCHINPUT") == 0:
-                cmd += "/DWINVER=0x601 "
-            else:
-                cmd += "/DWINVER=0x501 "
+            # We still target Windows XP.
+            cmd += "/DWINVER=0x501 "
+            # Work around a WinXP/2003 bug when using VS 2015+.
+            if SDK.get("VISUALSTUDIO_VERSION") == '14.0':
+                cmd += "/Zc:threadSafeInit- "
+
             cmd += "/Fo" + obj + " /nologo /c"
             cmd += "/Fo" + obj + " /nologo /c"
             if GetTargetArch() != 'x64' and (not PkgSkip("SSE2") or 'SSE2' in opts):
             if GetTargetArch() != 'x64' and (not PkgSkip("SSE2") or 'SSE2' in opts):
                 cmd += " /arch:SSE2"
                 cmd += " /arch:SSE2"
@@ -1109,12 +1112,7 @@ def CompileCxx(obj,src,opts):
             if GetTargetArch() == 'x64':
             if GetTargetArch() == 'x64':
                 cmd += "/favor:blend "
                 cmd += "/favor:blend "
             cmd += "/wd4996 /wd4275 /wd4267 /wd4101 /wd4273 "
             cmd += "/wd4996 /wd4275 /wd4267 /wd4101 /wd4273 "
-
-            # Enable Windows 7 interfaces if we need Touchinput.
-            if PkgSkip("TOUCHINPUT") == 0:
-                cmd += "/DWINVER=0x601 "
-            else:
-                cmd += "/DWINVER=0x501 "
+            cmd += "/DWINVER=0x501 "
             cmd += "/Fo" + obj + " /c"
             cmd += "/Fo" + obj + " /c"
             for x in ipath: cmd += " /I" + x
             for x in ipath: cmd += " /I" + x
             for (opt,dir) in INCDIRECTORIES:
             for (opt,dir) in INCDIRECTORIES:
@@ -1196,7 +1194,7 @@ def CompileCxx(obj,src,opts):
 
 
     if (COMPILER=="GCC"):
     if (COMPILER=="GCC"):
         if (src.endswith(".c")): cmd = GetCC() +' -fPIC -c -o ' + obj
         if (src.endswith(".c")): cmd = GetCC() +' -fPIC -c -o ' + obj
-        else:                    cmd = GetCXX()+' -ftemplate-depth-70 -fPIC -c -o ' + obj
+        else:                    cmd = GetCXX()+' -std=gnu++0x -ftemplate-depth-70 -fPIC -c -o ' + obj
         for (opt, dir) in INCDIRECTORIES:
         for (opt, dir) in INCDIRECTORIES:
             if (opt=="ALWAYS") or (opt in opts): cmd += ' -I' + BracketNameWithQuotes(dir)
             if (opt=="ALWAYS") or (opt in opts): cmd += ' -I' + BracketNameWithQuotes(dir)
         for (opt, dir) in FRAMEWORKDIRECTORIES:
         for (opt, dir) in FRAMEWORKDIRECTORIES:
@@ -1682,11 +1680,7 @@ def CompileLink(dll, obj, opts):
                 if 'NOARCH:' + arch.upper() not in opts:
                 if 'NOARCH:' + arch.upper() not in opts:
                     cmd += " -arch %s" % arch
                     cmd += " -arch %s" % arch
 
 
-        if "SYSROOT" in SDK:
-            cmd += " --sysroot=%s -no-canonical-prefixes" % (SDK["SYSROOT"])
-
-        # Android-specific flags.
-        if GetTarget() == 'android':
+        elif GetTarget() == 'android':
             cmd += " -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now"
             cmd += " -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now"
             if GetTargetArch() == 'armv7a':
             if GetTargetArch() == 'armv7a':
                 cmd += " -march=armv7-a -Wl,--fix-cortex-a8"
                 cmd += " -march=armv7-a -Wl,--fix-cortex-a8"
@@ -1694,9 +1688,17 @@ def CompileLink(dll, obj, opts):
         else:
         else:
             cmd += " -pthread"
             cmd += " -pthread"
 
 
+        if "SYSROOT" in SDK:
+            cmd += " --sysroot=%s -no-canonical-prefixes" % (SDK["SYSROOT"])
+
         if LDFLAGS != "":
         if LDFLAGS != "":
             cmd += " " + LDFLAGS
             cmd += " " + LDFLAGS
 
 
+        # Don't link libraries with Python.
+        if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST:
+            opts = opts[:]
+            opts.remove("PYTHON")
+
         for (opt, dir) in LIBDIRECTORIES:
         for (opt, dir) in LIBDIRECTORIES:
             if (opt=="ALWAYS") or (opt in opts):
             if (opt=="ALWAYS") or (opt in opts):
                 cmd += ' -L' + BracketNameWithQuotes(dir)
                 cmd += ' -L' + BracketNameWithQuotes(dir)
@@ -2122,17 +2124,13 @@ DTOOL_CONFIG=[
     ("COMPILE_IN_DEFAULT_FONT",        '1',                      '1'),
     ("COMPILE_IN_DEFAULT_FONT",        '1',                      '1'),
     ("STDFLOAT_DOUBLE",                'UNDEF',                  'UNDEF'),
     ("STDFLOAT_DOUBLE",                'UNDEF',                  'UNDEF'),
     ("HAVE_MAYA",                      '1',                      '1'),
     ("HAVE_MAYA",                      '1',                      '1'),
-    ("MAYA_PRE_5_0",                   'UNDEF',                  'UNDEF'),
     ("HAVE_SOFTIMAGE",                 'UNDEF',                  'UNDEF'),
     ("HAVE_SOFTIMAGE",                 'UNDEF',                  'UNDEF'),
-    ("SSL_097",                        'UNDEF',                  'UNDEF'),
     ("REPORT_OPENSSL_ERRORS",          '1',                      '1'),
     ("REPORT_OPENSSL_ERRORS",          '1',                      '1'),
     ("USE_PANDAFILESTREAM",            '1',                      '1'),
     ("USE_PANDAFILESTREAM",            '1',                      '1'),
     ("USE_DELETED_CHAIN",              '1',                      '1'),
     ("USE_DELETED_CHAIN",              '1',                      '1'),
-    ("HAVE_WIN_TOUCHINPUT",            'UNDEF',                  'UNDEF'),
     ("HAVE_GLX",                       'UNDEF',                  '1'),
     ("HAVE_GLX",                       'UNDEF',                  '1'),
     ("HAVE_WGL",                       '1',                      'UNDEF'),
     ("HAVE_WGL",                       '1',                      'UNDEF'),
     ("HAVE_DX9",                       'UNDEF',                  'UNDEF'),
     ("HAVE_DX9",                       'UNDEF',                  'UNDEF'),
-    ("HAVE_CHROMIUM",                  'UNDEF',                  'UNDEF'),
     ("HAVE_THREADS",                   '1',                      '1'),
     ("HAVE_THREADS",                   '1',                      '1'),
     ("SIMPLE_THREADS",                 'UNDEF',                  'UNDEF'),
     ("SIMPLE_THREADS",                 'UNDEF',                  'UNDEF'),
     ("OS_SIMPLE_THREADS",              '1',                      '1'),
     ("OS_SIMPLE_THREADS",              '1',                      '1'),
@@ -2145,12 +2143,9 @@ DTOOL_CONFIG=[
     ("DO_COLLISION_RECORDING",         'UNDEF',                  'UNDEF'),
     ("DO_COLLISION_RECORDING",         'UNDEF',                  'UNDEF'),
     ("SUPPORT_IMMEDIATE_MODE",         'UNDEF',                  'UNDEF'),
     ("SUPPORT_IMMEDIATE_MODE",         'UNDEF',                  'UNDEF'),
     ("SUPPORT_FIXED_FUNCTION",         '1',                      '1'),
     ("SUPPORT_FIXED_FUNCTION",         '1',                      '1'),
-    ("TRACK_IN_INTERPRETER",           'UNDEF',                  'UNDEF'),
     ("DO_MEMORY_USAGE",                'UNDEF',                  'UNDEF'),
     ("DO_MEMORY_USAGE",                'UNDEF',                  'UNDEF'),
     ("DO_PIPELINING",                  '1',                      '1'),
     ("DO_PIPELINING",                  '1',                      '1'),
     ("EXPORT_TEMPLATES",               'yes',                    'yes'),
     ("EXPORT_TEMPLATES",               'yes',                    'yes'),
-    ("LINK_IN_GL",                     'UNDEF',                  'UNDEF'),
-    ("LINK_IN_PHYSICS",                'UNDEF',                  'UNDEF'),
     ("DEFAULT_PATHSEP",                '";"',                    '":"'),
     ("DEFAULT_PATHSEP",                '";"',                    '":"'),
     ("WORDS_BIGENDIAN",                'UNDEF',                  'UNDEF'),
     ("WORDS_BIGENDIAN",                'UNDEF',                  'UNDEF'),
     ("HAVE_NAMESPACE",                 '1',                      '1'),
     ("HAVE_NAMESPACE",                 '1',                      '1'),
@@ -2206,13 +2201,9 @@ DTOOL_CONFIG=[
     ("PHAVE_STDINT_H",                 '1',                      '1'),
     ("PHAVE_STDINT_H",                 '1',                      '1'),
     ("HAVE_RTTI",                      '1',                      '1'),
     ("HAVE_RTTI",                      '1',                      '1'),
     ("HAVE_X11",                       'UNDEF',                  '1'),
     ("HAVE_X11",                       'UNDEF',                  '1'),
-    ("HAVE_XRANDR",                    'UNDEF',                  '1'),
-    ("HAVE_XF86DGA",                   'UNDEF',                  '1'),
-    ("HAVE_XCURSOR",                   'UNDEF',                  '1'),
     ("IS_LINUX",                       'UNDEF',                  '1'),
     ("IS_LINUX",                       'UNDEF',                  '1'),
     ("IS_OSX",                         'UNDEF',                  'UNDEF'),
     ("IS_OSX",                         'UNDEF',                  'UNDEF'),
     ("IS_FREEBSD",                     'UNDEF',                  'UNDEF'),
     ("IS_FREEBSD",                     'UNDEF',                  'UNDEF'),
-    ("GLOBAL_OPERATOR_NEW_EXCEPTIONS", 'UNDEF',                  '1'),
     ("HAVE_EIGEN",                     'UNDEF',                  'UNDEF'),
     ("HAVE_EIGEN",                     'UNDEF',                  'UNDEF'),
     ("LINMATH_ALIGN",                  '1',                      '1'),
     ("LINMATH_ALIGN",                  '1',                      '1'),
     ("HAVE_ZLIB",                      'UNDEF',                  'UNDEF'),
     ("HAVE_ZLIB",                      'UNDEF',                  'UNDEF'),
@@ -2230,28 +2221,25 @@ DTOOL_CONFIG=[
     ("HAVE_PNM",                       '1',                      '1'),
     ("HAVE_PNM",                       '1',                      '1'),
     ("HAVE_STB_IMAGE",                 '1',                      '1'),
     ("HAVE_STB_IMAGE",                 '1',                      '1'),
     ("HAVE_VORBIS",                    'UNDEF',                  'UNDEF'),
     ("HAVE_VORBIS",                    'UNDEF',                  'UNDEF'),
-    ("HAVE_NVIDIACG",                  'UNDEF',                  'UNDEF'),
     ("HAVE_FREETYPE",                  'UNDEF',                  'UNDEF'),
     ("HAVE_FREETYPE",                  'UNDEF',                  'UNDEF'),
     ("HAVE_FFTW",                      'UNDEF',                  'UNDEF'),
     ("HAVE_FFTW",                      'UNDEF',                  'UNDEF'),
     ("HAVE_OPENSSL",                   'UNDEF',                  'UNDEF'),
     ("HAVE_OPENSSL",                   'UNDEF',                  'UNDEF'),
     ("HAVE_NET",                       'UNDEF',                  'UNDEF'),
     ("HAVE_NET",                       'UNDEF',                  'UNDEF'),
+    ("WANT_NATIVE_NET",                '1',                      '1'),
+    ("SIMULATE_NETWORK_DELAY",         'UNDEF',                  'UNDEF'),
     ("HAVE_EGG",                       '1',                      '1'),
     ("HAVE_EGG",                       '1',                      '1'),
     ("HAVE_CG",                        'UNDEF',                  'UNDEF'),
     ("HAVE_CG",                        'UNDEF',                  'UNDEF'),
     ("HAVE_CGGL",                      'UNDEF',                  'UNDEF'),
     ("HAVE_CGGL",                      'UNDEF',                  'UNDEF'),
     ("HAVE_CGDX9",                     'UNDEF',                  'UNDEF'),
     ("HAVE_CGDX9",                     'UNDEF',                  'UNDEF'),
-    ("HAVE_FFMPEG",                    'UNDEF',                  'UNDEF'),
-    ("HAVE_SWSCALE",                   'UNDEF',                  'UNDEF'),
-    ("HAVE_SWRESAMPLE",                'UNDEF',                  'UNDEF'),
     ("HAVE_ARTOOLKIT",                 'UNDEF',                  'UNDEF'),
     ("HAVE_ARTOOLKIT",                 'UNDEF',                  'UNDEF'),
-    ("HAVE_OPENCV",                    'UNDEF',                  'UNDEF'),
     ("HAVE_DIRECTCAM",                 'UNDEF',                  'UNDEF'),
     ("HAVE_DIRECTCAM",                 'UNDEF',                  'UNDEF'),
     ("HAVE_SQUISH",                    'UNDEF',                  'UNDEF'),
     ("HAVE_SQUISH",                    'UNDEF',                  'UNDEF'),
-    ("HAVE_FCOLLADA",                  'UNDEF',                  'UNDEF'),
     ("HAVE_CARBON",                    'UNDEF',                  'UNDEF'),
     ("HAVE_CARBON",                    'UNDEF',                  'UNDEF'),
     ("HAVE_COCOA",                     'UNDEF',                  'UNDEF'),
     ("HAVE_COCOA",                     'UNDEF',                  'UNDEF'),
     ("HAVE_OPENAL_FRAMEWORK",          'UNDEF',                  'UNDEF'),
     ("HAVE_OPENAL_FRAMEWORK",          'UNDEF',                  'UNDEF'),
     ("HAVE_ROCKET_PYTHON",             '1',                      '1'),
     ("HAVE_ROCKET_PYTHON",             '1',                      '1'),
     ("HAVE_ROCKET_DEBUGGER",           'UNDEF',                  'UNDEF'),
     ("HAVE_ROCKET_DEBUGGER",           'UNDEF',                  'UNDEF'),
+    ("USE_TAU",                        'UNDEF',                  'UNDEF'),
     ("PRC_SAVE_DESCRIPTIONS",          '1',                      '1'),
     ("PRC_SAVE_DESCRIPTIONS",          '1',                      '1'),
 #    ("_SECURE_SCL",                    '0',                      'UNDEF'),
 #    ("_SECURE_SCL",                    '0',                      'UNDEF'),
 #    ("_SECURE_SCL_THROWS",             '0',                      'UNDEF'),
 #    ("_SECURE_SCL_THROWS",             '0',                      'UNDEF'),
@@ -2298,9 +2286,6 @@ def WriteConfigSettings():
             else:
             else:
                 dtool_config["HAVE_"+x] = 'UNDEF'
                 dtool_config["HAVE_"+x] = 'UNDEF'
 
 
-    if not PkgSkip("OPENCV"):
-        dtool_config["OPENCV_VER_23"] = '1' if OPENCV_VER_23 else 'UNDEF'
-
     dtool_config["HAVE_NET"] = '1'
     dtool_config["HAVE_NET"] = '1'
 
 
     if (PkgSkip("NVIDIACG")==0):
     if (PkgSkip("NVIDIACG")==0):
@@ -2320,9 +2305,6 @@ def WriteConfigSettings():
         dtool_config["PHAVE_SYS_MALLOC_H"] = '1'
         dtool_config["PHAVE_SYS_MALLOC_H"] = '1'
         dtool_config["HAVE_OPENAL_FRAMEWORK"] = '1'
         dtool_config["HAVE_OPENAL_FRAMEWORK"] = '1'
         dtool_config["HAVE_X11"] = 'UNDEF'  # We might have X11, but we don't need it.
         dtool_config["HAVE_X11"] = 'UNDEF'  # We might have X11, but we don't need it.
-        dtool_config["HAVE_XRANDR"] = 'UNDEF'
-        dtool_config["HAVE_XF86DGA"] = 'UNDEF'
-        dtool_config["HAVE_XCURSOR"] = 'UNDEF'
         dtool_config["HAVE_GLX"] = 'UNDEF'
         dtool_config["HAVE_GLX"] = 'UNDEF'
         dtool_config["IS_LINUX"] = 'UNDEF'
         dtool_config["IS_LINUX"] = 'UNDEF'
         dtool_config["HAVE_VIDEO4LINUX"] = 'UNDEF'
         dtool_config["HAVE_VIDEO4LINUX"] = 'UNDEF'
@@ -2357,9 +2339,6 @@ def WriteConfigSettings():
     if (PkgSkip("PYTHON") != 0):
     if (PkgSkip("PYTHON") != 0):
         dtool_config["HAVE_ROCKET_PYTHON"] = 'UNDEF'
         dtool_config["HAVE_ROCKET_PYTHON"] = 'UNDEF'
 
 
-    if (PkgSkip("TOUCHINPUT") == 0 and GetTarget() == "windows"):
-        dtool_config["HAVE_WIN_TOUCHINPUT"] = '1'
-
     if (GetOptimize() <= 3):
     if (GetOptimize() <= 3):
         dtool_config["HAVE_ROCKET_DEBUGGER"] = '1'
         dtool_config["HAVE_ROCKET_DEBUGGER"] = '1'
 
 
@@ -2373,9 +2352,6 @@ def WriteConfigSettings():
     if (GetOptimize() <= 3):
     if (GetOptimize() <= 3):
         dtool_config["DO_COLLISION_RECORDING"] = '1'
         dtool_config["DO_COLLISION_RECORDING"] = '1'
 
 
-    #if (GetOptimize() <= 2):
-    #    dtool_config["TRACK_IN_INTERPRETER"] = '1'
-
     if (GetOptimize() <= 3):
     if (GetOptimize() <= 3):
         dtool_config["DO_MEMORY_USAGE"] = '1'
         dtool_config["DO_MEMORY_USAGE"] = '1'
 
 
@@ -2790,8 +2766,13 @@ if (GetTarget() == 'darwin'):
     # OpenAL is not yet working well on OSX for us, so let's do this for now.
     # OpenAL is not yet working well on OSX for us, so let's do this for now.
     configprc = configprc.replace("p3openal_audio", "p3fmod_audio")
     configprc = configprc.replace("p3openal_audio", "p3fmod_audio")
 
 
-ConditionalWriteFile(GetOutputDir()+"/etc/Config.prc", configprc)
-ConditionalWriteFile(GetOutputDir()+"/etc/Confauto.prc", confautoprc)
+if GetTarget() == 'windows':
+    # Convert to Windows newlines.
+    ConditionalWriteFile(GetOutputDir()+"/etc/Config.prc", configprc, newline='\r\n')
+    ConditionalWriteFile(GetOutputDir()+"/etc/Confauto.prc", confautoprc, newline='\r\n')
+else:
+    ConditionalWriteFile(GetOutputDir()+"/etc/Config.prc", configprc)
+    ConditionalWriteFile(GetOutputDir()+"/etc/Confauto.prc", confautoprc)
 
 
 ##########################################################################################
 ##########################################################################################
 #
 #
@@ -2888,22 +2869,75 @@ if tp_dir is not None:
 
 
     if GetTarget() == 'windows':
     if GetTarget() == 'windows':
         CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/")
         CopyAllFiles(GetOutputDir() + "/bin/", tp_dir + "extras/bin/")
-        if not PkgSkip("PYTHON"):
-            pydll = "/" + SDK["PYTHONVERSION"].replace(".", "")
-            if (GetOptimize() <= 2): pydll += "_d.dll"
-            else: pydll += ".dll"
-            CopyFile(GetOutputDir() + "/bin" + pydll, SDK["PYTHON"] + pydll)
-
-            for fn in glob.glob(SDK["PYTHON"] + "/vcruntime*.dll"):
-                CopyFile(GetOutputDir() + "/bin/", fn)
-
-            if not RTDIST:
-                CopyTree(GetOutputDir() + "/python", SDK["PYTHON"])
-                if not os.path.isfile(SDK["PYTHON"] + "/ppython.exe") and os.path.isfile(SDK["PYTHON"] + "/python.exe"):
-                    CopyFile(GetOutputDir() + "/python/ppython.exe", SDK["PYTHON"] + "/python.exe")
-                if not os.path.isfile(SDK["PYTHON"] + "/ppythonw.exe") and os.path.isfile(SDK["PYTHON"] + "/pythonw.exe"):
-                    CopyFile(GetOutputDir() + "/python/ppythonw.exe", SDK["PYTHON"] + "/pythonw.exe")
-                ConditionalWriteFile(GetOutputDir() + "/python/panda.pth", "..\n../bin\n")
+
+        if not PkgSkip("PYTHON") and not RTDIST:
+            #XXX rdb I don't think we need to copy over the Python DLL, do we?
+            #pydll = "/" + SDK["PYTHONVERSION"].replace(".", "")
+            #if (GetOptimize() <= 2): pydll += "_d.dll"
+            #else: pydll += ".dll"
+            #CopyFile(GetOutputDir() + "/bin" + pydll, SDK["PYTHON"] + pydll)
+
+            #for fn in glob.glob(SDK["PYTHON"] + "/vcruntime*.dll"):
+            #    CopyFile(GetOutputDir() + "/bin/", fn)
+
+            # Copy the whole Python directory.
+            CopyTree(GetOutputDir() + "/python", SDK["PYTHON"])
+
+            # NB: Python does not always ship with the correct manifest/dll.
+            # Figure out the correct one to ship, and grab it from WinSxS dir.
+            manifest = GetOutputDir() + '/tmp/python.manifest'
+            if os.path.isfile(manifest):
+                os.unlink(manifest)
+            oscmd('mt -inputresource:"%s\\python.exe";#1 -out:"%s" -nologo' % (SDK["PYTHON"], manifest), True)
+
+            if os.path.isfile(manifest):
+                import xml.etree.ElementTree as ET
+                tree = ET.parse(manifest)
+                idents = tree.findall('./{urn:schemas-microsoft-com:asm.v1}dependency/{urn:schemas-microsoft-com:asm.v1}dependentAssembly/{urn:schemas-microsoft-com:asm.v1}assemblyIdentity')
+            else:
+                idents = ()
+
+            for ident in tree.findall('./{urn:schemas-microsoft-com:asm.v1}dependency/{urn:schemas-microsoft-com:asm.v1}dependentAssembly/{urn:schemas-microsoft-com:asm.v1}assemblyIdentity'):
+                sxs_name = '_'.join([
+                    ident.get('processorArchitecture'),
+                    ident.get('name').lower(),
+                    ident.get('publicKeyToken'),
+                    ident.get('version'),
+                ])
+
+                # Find the manifest matching these parameters.
+                pattern = os.path.join('C:' + os.sep, 'Windows', 'WinSxS', 'Manifests', sxs_name + '_*.manifest')
+                manifests = glob.glob(pattern)
+                if not manifests:
+                    print("%sWARNING:%s Could not locate manifest %s.  You may need to reinstall the Visual C++ Redistributable." % (GetColor("red"), GetColor(), pattern))
+                    continue
+
+                CopyFile(GetOutputDir() + "/python/" + ident.get('name') + ".manifest", manifests[0])
+
+                # Also copy the corresponding msvcr dll.
+                pattern = os.path.join('C:' + os.sep, 'Windows', 'WinSxS', sxs_name + '_*', 'msvcr*.dll')
+                for file in glob.glob(pattern):
+                    CopyFile(GetOutputDir() + "/python/", file)
+
+            # Copy python.exe to ppython.exe.
+            if not os.path.isfile(SDK["PYTHON"] + "/ppython.exe") and os.path.isfile(SDK["PYTHON"] + "/python.exe"):
+                CopyFile(GetOutputDir() + "/python/ppython.exe", SDK["PYTHON"] + "/python.exe")
+            if not os.path.isfile(SDK["PYTHON"] + "/ppythonw.exe") and os.path.isfile(SDK["PYTHON"] + "/pythonw.exe"):
+                CopyFile(GetOutputDir() + "/python/ppythonw.exe", SDK["PYTHON"] + "/pythonw.exe")
+            ConditionalWriteFile(GetOutputDir() + "/python/panda.pth", "..\n../bin\n")
+
+# Copy over the MSVC runtime.
+if GetTarget() == 'windows' and "VISUALSTUDIO" in SDK:
+    vcver = SDK["VISUALSTUDIO_VERSION"].replace('.', '')
+    crtname = "Microsoft.VC%s.CRT" % (vcver)
+    dir = os.path.join(SDK["VISUALSTUDIO"], "VC", "redist", GetTargetArch(), crtname)
+
+    if os.path.isfile(os.path.join(dir, "msvcr" + vcver + ".dll")):
+        CopyFile(GetOutputDir() + "/bin/", os.path.join(dir, "msvcr" + vcver + ".dll"))
+    if os.path.isfile(os.path.join(dir, "msvcp" + vcver + ".dll")):
+        CopyFile(GetOutputDir() + "/bin/", os.path.join(dir, "msvcp" + vcver + ".dll"))
+    if os.path.isfile(os.path.join(dir, "vcruntime" + vcver + ".dll")):
+        CopyFile(GetOutputDir() + "/bin/", os.path.join(dir, "vcruntime" + vcver + ".dll"))
 
 
 ########################################################################
 ########################################################################
 ##
 ##
@@ -2911,8 +2945,14 @@ if tp_dir is not None:
 ##
 ##
 ########################################################################
 ########################################################################
 
 
-CopyFile(GetOutputDir()+"/", "doc/LICENSE")
-CopyFile(GetOutputDir()+"/", "doc/ReleaseNotes")
+if GetTarget() == 'windows':
+    # Convert to Windows newlines so they can be opened by notepad.
+    WriteFile(GetOutputDir() + "/LICENSE", ReadFile("doc/LICENSE"), newline='\r\n')
+    WriteFile(GetOutputDir() + "/ReleaseNotes", ReadFile("doc/ReleaseNotes"), newline='\r\n')
+else:
+    CopyFile(GetOutputDir()+"/", "doc/LICENSE")
+    CopyFile(GetOutputDir()+"/", "doc/ReleaseNotes")
+
 if (PkgSkip("PANDATOOL")==0):
 if (PkgSkip("PANDATOOL")==0):
     CopyAllFiles(GetOutputDir()+"/plugins/",  "pandatool/src/scripts/", ".mel")
     CopyAllFiles(GetOutputDir()+"/plugins/",  "pandatool/src/scripts/", ".mel")
     CopyAllFiles(GetOutputDir()+"/plugins/",  "pandatool/src/scripts/", ".ms")
     CopyAllFiles(GetOutputDir()+"/plugins/",  "pandatool/src/scripts/", ".ms")
@@ -3301,6 +3341,7 @@ if (not RUNTIME):
   TargetAdd('interrogate.exe', input='libp3cppParser.ilb')
   TargetAdd('interrogate.exe', input='libp3cppParser.ilb')
   TargetAdd('interrogate.exe', input=COMMON_DTOOL_LIBS)
   TargetAdd('interrogate.exe', input=COMMON_DTOOL_LIBS)
   TargetAdd('interrogate.exe', input='libp3interrogatedb.dll')
   TargetAdd('interrogate.exe', input='libp3interrogatedb.dll')
+  TargetAdd('interrogate.exe', input='libp3pystub.lib')
   TargetAdd('interrogate.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
   TargetAdd('interrogate.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
 
 
   TargetAdd('interrogate_module_interrogate_module.obj', opts=OPTS, input='interrogate_module.cxx')
   TargetAdd('interrogate_module_interrogate_module.obj', opts=OPTS, input='interrogate_module.cxx')
@@ -3308,6 +3349,7 @@ if (not RUNTIME):
   TargetAdd('interrogate_module.exe', input='libp3cppParser.ilb')
   TargetAdd('interrogate_module.exe', input='libp3cppParser.ilb')
   TargetAdd('interrogate_module.exe', input=COMMON_DTOOL_LIBS)
   TargetAdd('interrogate_module.exe', input=COMMON_DTOOL_LIBS)
   TargetAdd('interrogate_module.exe', input='libp3interrogatedb.dll')
   TargetAdd('interrogate_module.exe', input='libp3interrogatedb.dll')
+  TargetAdd('interrogate_module.exe', input='libp3pystub.lib')
   TargetAdd('interrogate_module.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
   TargetAdd('interrogate_module.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
 
 
   if (not RTDIST):
   if (not RTDIST):
@@ -3316,6 +3358,7 @@ if (not RUNTIME):
     TargetAdd('parse_file.exe', input='libp3cppParser.ilb')
     TargetAdd('parse_file.exe', input='libp3cppParser.ilb')
     TargetAdd('parse_file.exe', input=COMMON_DTOOL_LIBS)
     TargetAdd('parse_file.exe', input=COMMON_DTOOL_LIBS)
     TargetAdd('parse_file.exe', input='libp3interrogatedb.dll')
     TargetAdd('parse_file.exe', input='libp3interrogatedb.dll')
+    TargetAdd('parse_file.exe', input='libp3pystub.lib')
     TargetAdd('parse_file.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
     TargetAdd('parse_file.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
 
 
 #
 #
@@ -3339,6 +3382,7 @@ if (not RTDIST and not RUNTIME):
   TargetAdd('test_interrogate.exe', input='test_interrogate_test_interrogate.obj')
   TargetAdd('test_interrogate.exe', input='test_interrogate_test_interrogate.obj')
   TargetAdd('test_interrogate.exe', input='libp3interrogatedb.dll')
   TargetAdd('test_interrogate.exe', input='libp3interrogatedb.dll')
   TargetAdd('test_interrogate.exe', input=COMMON_DTOOL_LIBS)
   TargetAdd('test_interrogate.exe', input=COMMON_DTOOL_LIBS)
+  TargetAdd('test_interrogate.exe', input='libp3pystub.lib')
   TargetAdd('test_interrogate.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
   TargetAdd('test_interrogate.exe', opts=['ADVAPI',  'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER'])
 
 
 #
 #
@@ -4070,8 +4114,20 @@ if (not RUNTIME):
 #
 #
 
 
 if (PkgSkip("VISION") == 0) and (not RUNTIME):
 if (PkgSkip("VISION") == 0) and (not RUNTIME):
+  # We want to know whether we have ffmpeg so that we can override the .avi association.
+  if not PkgSkip("FFMPEG"):
+    DefSymbol("OPENCV", "HAVE_FFMPEG")
+  if not PkgSkip("OPENCV"):
+    DefSymbol("OPENCV", "HAVE_OPENCV")
+    if OPENCV_VER_23:
+        DefSymbol("OPENCV", "OPENCV_VER_23")
+
   OPTS=['DIR:panda/src/vision', 'BUILDING:VISION', 'ARTOOLKIT', 'OPENCV', 'DX9', 'DIRECTCAM', 'JPEG', 'EXCEPTIONS']
   OPTS=['DIR:panda/src/vision', 'BUILDING:VISION', 'ARTOOLKIT', 'OPENCV', 'DX9', 'DIRECTCAM', 'JPEG', 'EXCEPTIONS']
-  TargetAdd('p3vision_composite1.obj', opts=OPTS, input='p3vision_composite1.cxx')
+  TargetAdd('p3vision_composite1.obj', opts=OPTS, input='p3vision_composite1.cxx', dep=[
+    'dtool_have_ffmpeg.dat',
+    'dtool_have_opencv.dat',
+    'dtool_have_directcam.dat',
+  ])
 
 
   TargetAdd('libp3vision.dll', input='p3vision_composite1.obj')
   TargetAdd('libp3vision.dll', input='p3vision_composite1.obj')
   TargetAdd('libp3vision.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libp3vision.dll', input=COMMON_PANDA_LIBS)
@@ -4260,8 +4316,15 @@ if (PkgSkip("VRPN")==0 and not RUNTIME):
 # DIRECTORY: panda/src/ffmpeg
 # DIRECTORY: panda/src/ffmpeg
 #
 #
 if PkgSkip("FFMPEG") == 0 and not RUNTIME:
 if PkgSkip("FFMPEG") == 0 and not RUNTIME:
+  if not PkgSkip("SWSCALE"):
+    DefSymbol("FFMPEG", "HAVE_SWSCALE")
+  if not PkgSkip("SWRESAMPLE"):
+    DefSymbol("FFMPEG", "HAVE_SWRESAMPLE")
+
   OPTS=['DIR:panda/src/ffmpeg', 'BUILDING:FFMPEG', 'FFMPEG', 'SWSCALE', 'SWRESAMPLE']
   OPTS=['DIR:panda/src/ffmpeg', 'BUILDING:FFMPEG', 'FFMPEG', 'SWSCALE', 'SWRESAMPLE']
-  TargetAdd('p3ffmpeg_composite1.obj', opts=OPTS, input='p3ffmpeg_composite1.cxx')
+  TargetAdd('p3ffmpeg_composite1.obj', opts=OPTS, input='p3ffmpeg_composite1.cxx', dep=[
+    'dtool_have_swscale.dat', 'dtool_have_swresample.dat'])
+
   TargetAdd('libp3ffmpeg.dll', input='p3ffmpeg_composite1.obj')
   TargetAdd('libp3ffmpeg.dll', input='p3ffmpeg_composite1.obj')
   TargetAdd('libp3ffmpeg.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libp3ffmpeg.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libp3ffmpeg.dll', opts=OPTS)
   TargetAdd('libp3ffmpeg.dll', opts=OPTS)
@@ -4425,8 +4488,17 @@ if (not RUNTIME):
 #
 #
 
 
 if (not RUNTIME):
 if (not RUNTIME):
-  OPTS=['DIR:panda/src/framework', 'BUILDING:FRAMEWORK']
-  TargetAdd('p3framework_composite1.obj', opts=OPTS, input='p3framework_composite1.cxx')
+  deps = []
+  # Framework wants to link in a renderer when building statically, so tell it what is available.
+  if GetLinkAllStatic():
+    deps = ['dtool_have_gl.dat', 'dtool_have_tinydisplay.dat']
+    if not PkgSkip("GL"):
+      DefSymbol("FRAMEWORK", "HAVE_GL")
+    if not PkgSkip("TINYDISPLAY"):
+      DefSymbol("FRAMEWORK", "HAVE_TINYDISPLAY")
+
+  OPTS=['DIR:panda/src/framework', 'BUILDING:FRAMEWORK', 'FRAMEWORK']
+  TargetAdd('p3framework_composite1.obj', opts=OPTS, input='p3framework_composite1.cxx', dep=deps)
   TargetAdd('libp3framework.dll', input='p3framework_composite1.obj')
   TargetAdd('libp3framework.dll', input='p3framework_composite1.obj')
   TargetAdd('libp3framework.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libp3framework.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libp3framework.dll', opts=['ADVAPI'])
   TargetAdd('libp3framework.dll', opts=['ADVAPI'])
@@ -4514,7 +4586,7 @@ if (GetTarget() not in ['windows', 'darwin'] and PkgSkip("GL")==0 and PkgSkip("X
   TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj')
   TargetAdd('libpandagl.dll', input='p3glgsg_glgsg.obj')
   TargetAdd('libpandagl.dll', input='p3glxdisplay_composite1.obj')
   TargetAdd('libpandagl.dll', input='p3glxdisplay_composite1.obj')
   TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR'])
+  TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'X11'])
 
 
 #
 #
 # DIRECTORY: panda/src/cocoadisplay/
 # DIRECTORY: panda/src/cocoadisplay/
@@ -4532,7 +4604,7 @@ if (GetTarget() == 'darwin' and PkgSkip("COCOA")==0 and PkgSkip("GL")==0 and not
   if (PkgSkip('PANDAFX')==0):
   if (PkgSkip('PANDAFX')==0):
     TargetAdd('libpandagl.dll', input='libpandafx.dll')
     TargetAdd('libpandagl.dll', input='libpandafx.dll')
   TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libpandagl.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'COCOA'])
+  TargetAdd('libpandagl.dll', opts=['MODULE', 'GL', 'NVIDIACG', 'CGGL', 'COCOA', 'CARBON'])
 
 
 #
 #
 # DIRECTORY: panda/src/osxdisplay/
 # DIRECTORY: panda/src/osxdisplay/
@@ -4589,7 +4661,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES")==0 and PkgSkip("X11")==0 and not RUNTI
   TargetAdd('libpandagles.dll', input='p3glesgsg_glesgsg.obj')
   TargetAdd('libpandagles.dll', input='p3glesgsg_glesgsg.obj')
   TargetAdd('libpandagles.dll', input='pandagles_egldisplay_composite1.obj')
   TargetAdd('libpandagles.dll', input='pandagles_egldisplay_composite1.obj')
   TargetAdd('libpandagles.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libpandagles.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR'])
+  TargetAdd('libpandagles.dll', opts=['MODULE', 'GLES', 'EGL', 'X11'])
 
 
 #
 #
 # DIRECTORY: panda/src/egldisplay/
 # DIRECTORY: panda/src/egldisplay/
@@ -4607,7 +4679,7 @@ if (PkgSkip("EGL")==0 and PkgSkip("GLES2")==0 and PkgSkip("X11")==0 and not RUNT
   TargetAdd('libpandagles2.dll', input='p3gles2gsg_gles2gsg.obj')
   TargetAdd('libpandagles2.dll', input='p3gles2gsg_gles2gsg.obj')
   TargetAdd('libpandagles2.dll', input='pandagles2_egldisplay_composite1.obj')
   TargetAdd('libpandagles2.dll', input='pandagles2_egldisplay_composite1.obj')
   TargetAdd('libpandagles2.dll', input=COMMON_PANDA_LIBS)
   TargetAdd('libpandagles2.dll', input=COMMON_PANDA_LIBS)
-  TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11', 'XRANDR', 'XF86DGA', 'XCURSOR'])
+  TargetAdd('libpandagles2.dll', opts=['MODULE', 'GLES2', 'EGL', 'X11'])
 
 
 #
 #
 # DIRECTORY: panda/src/ode/
 # DIRECTORY: panda/src/ode/
@@ -4903,7 +4975,7 @@ if (not RUNTIME and (GetTarget() in ('windows', 'darwin') or PkgSkip("X11")==0)
     TargetAdd('libp3tinydisplay.dll', opts=['WINIMM', 'WINGDI', 'WINKERNEL', 'WINOLDNAMES', 'WINUSER', 'WINMM'])
     TargetAdd('libp3tinydisplay.dll', opts=['WINIMM', 'WINGDI', 'WINKERNEL', 'WINOLDNAMES', 'WINUSER', 'WINMM'])
   else:
   else:
     TargetAdd('libp3tinydisplay.dll', input='p3x11display_composite1.obj')
     TargetAdd('libp3tinydisplay.dll', input='p3x11display_composite1.obj')
-    TargetAdd('libp3tinydisplay.dll', opts=['X11', 'XRANDR', 'XF86DGA', 'XCURSOR'])
+    TargetAdd('libp3tinydisplay.dll', opts=['X11'])
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite1.obj')
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite1.obj')
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite2.obj')
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_composite2.obj')
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_ztriangle_1.obj')
   TargetAdd('libp3tinydisplay.dll', input='p3tinydisplay_ztriangle_1.obj')
@@ -4921,7 +4993,7 @@ if (PkgSkip("DIRECT")==0):
   OPTS=['DIR:direct/src/directbase', 'PYTHON']
   OPTS=['DIR:direct/src/directbase', 'PYTHON']
   TargetAdd('p3directbase_directbase.obj', opts=OPTS+['BUILDING:DIRECT'], input='directbase.cxx')
   TargetAdd('p3directbase_directbase.obj', opts=OPTS+['BUILDING:DIRECT'], input='directbase.cxx')
 
 
-  if (PkgSkip("PYTHON")==0 and not RTDIST and not RUNTIME):
+  if not PkgSkip("PYTHON") and not RTDIST and not RUNTIME and not PkgSkip("DIRECTSCRIPTS"):
     DefSymbol("BUILDING:PACKPANDA", "IMPORT_MODULE", "direct.directscripts.packpanda")
     DefSymbol("BUILDING:PACKPANDA", "IMPORT_MODULE", "direct.directscripts.packpanda")
     TargetAdd('packpanda.obj', opts=OPTS+['BUILDING:PACKPANDA'], input='ppython.cxx')
     TargetAdd('packpanda.obj', opts=OPTS+['BUILDING:PACKPANDA'], input='ppython.cxx')
     TargetAdd('packpanda.exe', input='packpanda.obj')
     TargetAdd('packpanda.exe', input='packpanda.obj')
@@ -5080,7 +5152,7 @@ if (PkgSkip("DIRECT")==0):
   TargetAdd('direct.pyd', input='libp3direct.dll')
   TargetAdd('direct.pyd', input='libp3direct.dll')
   TargetAdd('direct.pyd', input='libp3interrogatedb.dll')
   TargetAdd('direct.pyd', input='libp3interrogatedb.dll')
   TargetAdd('direct.pyd', input=COMMON_PANDA_LIBS)
   TargetAdd('direct.pyd', input=COMMON_PANDA_LIBS)
-  TargetAdd('direct.pyd', opts=['PYTHON', 'OPENSSL', 'WINUSER', 'WINGDI'])
+  TargetAdd('direct.pyd', opts=['PYTHON', 'OPENSSL', 'WINUSER', 'WINGDI', 'WINSOCK2'])
 
 
 #
 #
 # DIRECTORY: direct/src/dcparse/
 # DIRECTORY: direct/src/dcparse/
@@ -5096,6 +5168,7 @@ if (PkgSkip("PYTHON")==0 and PkgSkip("DIRECT")==0 and not RTDIST and not RUNTIME
   TargetAdd('p3dcparse.exe', input='dcparse_dcparse.obj')
   TargetAdd('p3dcparse.exe', input='dcparse_dcparse.obj')
   TargetAdd('p3dcparse.exe', input='libp3direct.dll')
   TargetAdd('p3dcparse.exe', input='libp3direct.dll')
   TargetAdd('p3dcparse.exe', input=COMMON_PANDA_LIBS)
   TargetAdd('p3dcparse.exe', input=COMMON_PANDA_LIBS)
+  TargetAdd('p3dcparse.exe', input='libp3pystub.lib')
   TargetAdd('p3dcparse.exe', opts=['ADVAPI', 'PYTHON'])
   TargetAdd('p3dcparse.exe', opts=['ADVAPI', 'PYTHON'])
 
 
 #
 #
@@ -6005,8 +6078,11 @@ if (PkgSkip("PANDATOOL")==0):
 #
 #
 
 
 if (PkgSkip("PANDATOOL")==0):
 if (PkgSkip("PANDATOOL")==0):
+    if not PkgSkip("FCOLLADA"):
+        DefSymbol("FCOLLADA", "HAVE_FCOLLADA")
+
     OPTS=['DIR:pandatool/src/ptloader', 'DIR:pandatool/src/flt', 'DIR:pandatool/src/lwo', 'DIR:pandatool/src/xfile', 'DIR:pandatool/src/xfileegg', 'DIR:pandatool/src/daeegg', 'BUILDING:PTLOADER', 'FCOLLADA']
     OPTS=['DIR:pandatool/src/ptloader', 'DIR:pandatool/src/flt', 'DIR:pandatool/src/lwo', 'DIR:pandatool/src/xfile', 'DIR:pandatool/src/xfileegg', 'DIR:pandatool/src/daeegg', 'BUILDING:PTLOADER', 'FCOLLADA']
-    TargetAdd('p3ptloader_config_ptloader.obj', opts=OPTS, input='config_ptloader.cxx')
+    TargetAdd('p3ptloader_config_ptloader.obj', opts=OPTS, input='config_ptloader.cxx', dep='dtool_have_fcollada.dat')
     TargetAdd('p3ptloader_loaderFileTypePandatool.obj', opts=OPTS, input='loaderFileTypePandatool.cxx')
     TargetAdd('p3ptloader_loaderFileTypePandatool.obj', opts=OPTS, input='loaderFileTypePandatool.cxx')
     TargetAdd('libp3ptloader.dll', input='p3ptloader_config_ptloader.obj')
     TargetAdd('libp3ptloader.dll', input='p3ptloader_config_ptloader.obj')
     TargetAdd('libp3ptloader.dll', input='p3ptloader_loaderFileTypePandatool.obj')
     TargetAdd('libp3ptloader.dll', input='p3ptloader_loaderFileTypePandatool.obj')
@@ -6776,9 +6852,9 @@ def MakeInstallerLinux():
         txt = txt.replace("VERSION", DEBVERSION).replace("ARCH", pkg_arch).replace("PV", PV).replace("MAJOR", MAJOR_VERSION)
         txt = txt.replace("VERSION", DEBVERSION).replace("ARCH", pkg_arch).replace("PV", PV).replace("MAJOR", MAJOR_VERSION)
         txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024))
         txt = txt.replace("INSTSIZE", str(GetDirectorySize("targetroot") / 1024))
         oscmd("mkdir --mode=0755 -p targetroot/DEBIAN")
         oscmd("mkdir --mode=0755 -p targetroot/DEBIAN")
-        oscmd("cd targetroot ; (find usr -type f -exec md5sum {} \;) >  DEBIAN/md5sums")
+        oscmd("cd targetroot && (find usr -type f -exec md5sum {} ;) > DEBIAN/md5sums")
         if (not RUNTIME):
         if (not RUNTIME):
-          oscmd("cd targetroot ; (find etc -type f -exec md5sum {} \;) >> DEBIAN/md5sums")
+          oscmd("cd targetroot && (find etc -type f -exec md5sum {} ;) >> DEBIAN/md5sums")
           WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n")
           WriteFile("targetroot/DEBIAN/conffiles","/etc/Config.prc\n")
         WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n")
         WriteFile("targetroot/DEBIAN/postinst","#!/bin/sh\necho running ldconfig\nldconfig\n")
         oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm")
         oscmd("cp targetroot/DEBIAN/postinst targetroot/DEBIAN/postrm")
@@ -6806,7 +6882,7 @@ def MakeInstallerLinux():
 
 
         if RUNTIME:
         if RUNTIME:
             # The runtime doesn't export any useful symbols, so just query the dependencies.
             # 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())
+            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()
             depends = ReadFile("targetroot/debian/substvars").replace("shlibs:Depends=", "").strip()
             recommends = ""
             recommends = ""
         else:
         else:
@@ -6814,12 +6890,12 @@ def MakeInstallerLinux():
             pkg_dir = "debian/panda3d" + MAJOR_VERSION
             pkg_dir = "debian/panda3d" + MAJOR_VERSION
 
 
             # Generate a symbols file so that other packages can know which symbols we export.
             # 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())
+            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.
             # Library dependencies are required, binary dependencies are recommended.
             # We explicitly exclude libphysx-extras since we don't want to depend on PhysX.
             # 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())
+            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.
             # Parse the substvars files generated by dpkg-shlibdeps.
             depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip()
             depends = ReadFile("targetroot/debian/substvars_dep").replace("shlibs:Depends=", "").strip()
@@ -7181,6 +7257,11 @@ try:
             MakeInstallerFreeBSD()
             MakeInstallerFreeBSD()
         else:
         else:
             exit("Do not know how to make an installer for this platform")
             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:
 finally:
     SaveDependencyCache()
     SaveDependencyCache()
 
 

+ 51 - 6
makepanda/makepandacore.py

@@ -396,10 +396,16 @@ def CrossCompiling():
     return GetTarget() != GetHost()
     return GetTarget() != GetHost()
 
 
 def GetCC():
 def GetCC():
-    return os.environ.get('CC', TOOLCHAIN_PREFIX + 'gcc')
+    if TARGET == 'darwin':
+        return os.environ.get('CC', TOOLCHAIN_PREFIX + 'clang')
+    else:
+        return os.environ.get('CC', TOOLCHAIN_PREFIX + 'gcc')
 
 
 def GetCXX():
 def GetCXX():
-    return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'g++')
+    if TARGET == 'darwin':
+        return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'clang++')
+    else:
+        return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'g++')
 
 
 def GetStrip():
 def GetStrip():
     # Hack
     # Hack
@@ -512,6 +518,7 @@ def oscmd(cmd, ignoreError = False):
             exit("Cannot find "+exe+" on search path")
             exit("Cannot find "+exe+" on search path")
         res = os.spawnl(os.P_WAIT, exe_path, cmd)
         res = os.spawnl(os.P_WAIT, exe_path, cmd)
     else:
     else:
+        cmd = cmd.replace(';', '\\;')
         res = subprocess.call(cmd, shell=True)
         res = subprocess.call(cmd, shell=True)
         sig = res & 0x7F
         sig = res & 0x7F
         if (GetVerbose() and res != 0):
         if (GetVerbose() and res != 0):
@@ -966,7 +973,12 @@ def ReadBinaryFile(wfile):
         ex = sys.exc_info()[1]
         ex = sys.exc_info()[1]
         exit("Cannot read %s: %s" % (wfile, ex))
         exit("Cannot read %s: %s" % (wfile, ex))
 
 
-def WriteFile(wfile, data):
+def WriteFile(wfile, data, newline=None):
+    if newline is not None:
+        data = data.replace('\r\n', '\n')
+        data = data.replace('\r', '\n')
+        data = data.replace('\n', newline)
+
     try:
     try:
         dsthandle = open(wfile, "w")
         dsthandle = open(wfile, "w")
         dsthandle.write(data)
         dsthandle.write(data)
@@ -984,18 +996,24 @@ def WriteBinaryFile(wfile, data):
         ex = sys.exc_info()[1]
         ex = sys.exc_info()[1]
         exit("Cannot write to %s: %s" % (wfile, ex))
         exit("Cannot write to %s: %s" % (wfile, ex))
 
 
-def ConditionalWriteFile(dest, desiredcontents):
+def ConditionalWriteFile(dest, data, newline=None):
+    if newline is not None:
+        data = data.replace('\r\n', '\n')
+        data = data.replace('\r', '\n')
+        data = data.replace('\n', newline)
+
     try:
     try:
         rfile = open(dest, 'r')
         rfile = open(dest, 'r')
         contents = rfile.read(-1)
         contents = rfile.read(-1)
         rfile.close()
         rfile.close()
     except:
     except:
         contents = 0
         contents = 0
-    if contents != desiredcontents:
+
+    if contents != data:
         if VERBOSE:
         if VERBOSE:
             print("Writing %s" % (dest))
             print("Writing %s" % (dest))
         sys.stdout.flush()
         sys.stdout.flush()
-        WriteFile(dest, desiredcontents)
+        WriteFile(dest, data)
 
 
 def DeleteVCS(dir):
 def DeleteVCS(dir):
     if dir == "": dir = "."
     if dir == "": dir = "."
@@ -1984,6 +2002,11 @@ def SdkLocatePython(prefer_thirdparty_python=False):
          SDK["PYTHONVERSION"] = "python" + ver
          SDK["PYTHONVERSION"] = "python" + ver
          SDK["PYTHONEXEC"] = "/System/Library/Frameworks/Python.framework/Versions/" + ver + "/bin/python" + ver
          SDK["PYTHONEXEC"] = "/System/Library/Frameworks/Python.framework/Versions/" + ver + "/bin/python" + ver
 
 
+         # Avoid choosing the one in the thirdparty package dir.
+         PkgSetCustomLocation("PYTHON")
+         IncDirectory("PYTHON", py_fwx + "/include")
+         LibDirectory("PYTHON", "%s/usr/lib" % (SDK.get("MACOSX", "")))
+
          if sys.version[:3] != ver:
          if sys.version[:3] != ver:
              print("Warning: building with Python %s instead of %s since you targeted a specific Mac OS X version." % (ver, sys.version[:3]))
              print("Warning: building with Python %s instead of %s since you targeted a specific Mac OS X version." % (ver, sys.version[:3]))
 
 
@@ -2057,6 +2080,10 @@ def SdkLocateWindows(version = '7.1'):
         # Choose the latest version of the Windows 10 SDK.
         # Choose the latest version of the Windows 10 SDK.
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
 
 
+        # Fallback in case we can't read the registry.
+        if not platsdk or not os.path.isdir(platsdk):
+            platsdk = "C:\\Program Files (x86)\\Windows Kits\\10\\"
+
         if platsdk and os.path.isdir(platsdk):
         if platsdk and os.path.isdir(platsdk):
             incdirs = glob.glob(os.path.join(platsdk, 'Include', version + '.*.*'))
             incdirs = glob.glob(os.path.join(platsdk, 'Include', version + '.*.*'))
             max_version = ()
             max_version = ()
@@ -2089,6 +2116,10 @@ def SdkLocateWindows(version = '7.1'):
         # We chose a specific version of the Windows 10 SDK.  Verify it exists.
         # We chose a specific version of the Windows 10 SDK.  Verify it exists.
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
 
 
+        # Fallback in case we can't read the registry.
+        if not platsdk or not os.path.isdir(platsdk):
+            platsdk = "C:\\Program Files (x86)\\Windows Kits\\10\\"
+
         if version.count('.') == 2:
         if version.count('.') == 2:
             version += '.0'
             version += '.0'
 
 
@@ -2098,6 +2129,10 @@ def SdkLocateWindows(version = '7.1'):
     elif version == '8.1':
     elif version == '8.1':
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot81")
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot81")
 
 
+        # Fallback in case we can't read the registry.
+        if not platsdk or not os.path.isdir(platsdk):
+            platsdk = "C:\\Program Files (x86)\\Windows Kits\\8.1\\"
+
     elif version == '8.0':
     elif version == '8.0':
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot")
         platsdk = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot")
 
 
@@ -2403,9 +2438,19 @@ def SetupVisualStudioEnviron():
     # with Visual Studio 2015 requires use of the Universal CRT.
     # with Visual Studio 2015 requires use of the Universal CRT.
     if winsdk_ver == '7.1' and SDK["VISUALSTUDIO_VERSION"] == '14.0':
     if winsdk_ver == '7.1' and SDK["VISUALSTUDIO_VERSION"] == '14.0':
         win_kit = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
         win_kit = GetRegistryKey("SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", "KitsRoot10")
+
+        # Fallback in case we can't read the registry.
+        if not win_kit or not os.path.isdir(win_kit):
+            win_kit = "C:\\Program Files (x86)\\Windows Kits\\10\\"
+        elif not win_kit.endswith('\\'):
+            win_kit += '\\'
+
         AddToPathEnv("LIB", win_kit + "Lib\\10.0.10150.0\\ucrt\\" + arch)
         AddToPathEnv("LIB", win_kit + "Lib\\10.0.10150.0\\ucrt\\" + arch)
         AddToPathEnv("INCLUDE", win_kit + "Include\\10.0.10150.0\\ucrt")
         AddToPathEnv("INCLUDE", win_kit + "Include\\10.0.10150.0\\ucrt")
 
 
+        # Copy the DLLs to the bin directory.
+        CopyAllFiles(GetOutputDir() + "/bin/", win_kit + "Redist\\ucrt\\DLLs\\" + arch + "\\")
+
 ########################################################################
 ########################################################################
 #
 #
 # Include and Lib directories.
 # Include and Lib directories.

+ 598 - 0
makepanda/makewheel.py

@@ -0,0 +1,598 @@
+"""
+Generates a wheel (.whl) file from the output of makepanda.
+
+Since the wheel requires special linking, this will only work if compiled with
+the `--wheel` parameter.
+
+Please keep this file work with Panda3D 1.9 until that reaches EOL.
+"""
+from __future__ import print_function, unicode_literals
+from distutils.util import get_platform
+import json
+
+import sys
+import os
+from os.path import join
+import shutil
+import zipfile
+import hashlib
+import tempfile
+import subprocess
+from distutils.sysconfig import get_config_var
+from optparse import OptionParser
+from makepandacore import ColorText, LocateBinary, ParsePandaVersion, GetExtensionSuffix, SetVerbose, GetVerbose
+from base64 import urlsafe_b64encode
+
+
+default_platform = get_platform()
+
+if default_platform.startswith("linux-"):
+    # Is this manylinux1?
+    if os.path.isfile("/lib/libc-2.5.so") and os.path.isdir("/opt/python"):
+        default_platform = default_platform.replace("linux", "manylinux1")
+
+
+def get_abi_tag():
+    if sys.version_info >= (3, 0):
+        soabi = get_config_var('SOABI')
+        if soabi and soabi.startswith('cpython-'):
+            return 'cp' + soabi.split('-')[1]
+        elif soabi:
+            return soabi.replace('.', '_').replace('-', '_')
+
+    soabi = 'cp%d%d' % (sys.version_info[:2])
+
+    debug_flag = get_config_var('Py_DEBUG')
+    if (debug_flag is None and hasattr(sys, 'gettotalrefcount')) or debug_flag:
+        soabi += 'd'
+
+    malloc_flag = get_config_var('WITH_PYMALLOC')
+    if malloc_flag is None or malloc_flag:
+        soabi += 'm'
+
+    if sys.version_info < (3, 3):
+        usize = get_config_var('Py_UNICODE_SIZE')
+        if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4:
+            soabi += 'u'
+
+    return soabi
+
+
+def is_exe_file(path):
+    return os.path.isfile(path) and path.lower().endswith('.exe')
+
+
+def is_elf_file(path):
+    base = os.path.basename(path)
+    return os.path.isfile(path) and '.' not in base and \
+           open(path, 'rb').read(4) == b'\x7FELF'
+
+
+def is_mach_o_file(path):
+    base = os.path.basename(path)
+    return os.path.isfile(path) and '.' not in base and \
+           open(path, 'rb').read(4) in (b'\xCA\xFE\xBA\xBE', b'\xBE\xBA\xFE\bCA',
+                                        b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE',
+                                        b'\xFE\xED\xFA\xCF', b'\xCF\xFA\xED\xFE')
+
+def is_fat_file(path):
+    return os.path.isfile(path) and \
+           open(path, 'rb').read(4) in (b'\xCA\xFE\xBA\xBE', b'\xBE\xBA\xFE\bCA')
+
+
+if sys.platform in ('win32', 'cygwin'):
+    is_executable = is_exe_file
+elif sys.platform == 'darwin':
+    is_executable = is_mach_o_file
+else:
+    is_executable = is_elf_file
+
+
+# Other global parameters
+PY_VERSION = "cp{0}{1}".format(*sys.version_info)
+ABI_TAG = get_abi_tag()
+EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
+
+# Plug-ins to install.
+PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"]
+
+WHEEL_DATA = """Wheel-Version: 1.0
+Generator: makepanda
+Root-Is-Purelib: false
+Tag: {0}-{1}-{2}
+"""
+
+METADATA = {
+    "license": "BSD",
+    "name": "Panda3D",
+    "metadata_version": "2.0",
+    "generator": "makepanda",
+    "summary": "Panda3D is a game engine, a framework for 3D rendering and "
+               "game development for Python and C++ programs.",
+    "extensions": {
+        "python.details": {
+            "project_urls": {
+                "Home": "https://www.panda3d.org/"
+            },
+            "document_names": {
+                "license": "LICENSE.txt"
+            },
+            "contacts": [
+                {
+                    "role": "author",
+                    "email": "[email protected]",
+                    "name": "Panda3D Team"
+                }
+            ]
+        }
+    },
+    "classifiers": [
+        "Development Status :: 5 - Production/Stable",
+        "Intended Audience :: Developers",
+        "Intended Audience :: End Users/Desktop",
+        "License :: OSI Approved :: BSD License",
+        "Operating System :: OS Independent",
+        "Programming Language :: C++",
+        "Programming Language :: Python",
+        "Topic :: Games/Entertainment",
+        "Topic :: Multimedia",
+        "Topic :: Multimedia :: Graphics",
+        "Topic :: Multimedia :: Graphics :: 3D Rendering"
+    ]
+}
+
+PANDA3D_TOOLS_INIT = """import os, sys
+import panda3d
+
+if sys.platform in ('win32', 'cygwin'):
+    path_var = 'PATH'
+elif sys.platform == 'darwin':
+    path_var = 'DYLD_LIBRARY_PATH'
+else:
+    path_var = 'LD_LIBRARY_PATH'
+
+dir = os.path.dirname(panda3d.__file__)
+del panda3d
+if not os.environ.get(path_var):
+    os.environ[path_var] = dir
+else:
+    os.environ[path_var] = dir + os.pathsep + os.environ[path_var]
+
+del os, sys, path_var, dir
+
+
+def _exec_tool(tool):
+    import os, sys
+    from subprocess import Popen
+    tools_dir = os.path.dirname(__file__)
+    handle = Popen(sys.argv, executable=os.path.join(tools_dir, tool))
+    try:
+        try:
+            return handle.wait()
+        except KeyboardInterrupt:
+            # Give the program a chance to handle the signal gracefully.
+            return handle.wait()
+    except:
+        handle.kill()
+        handle.wait()
+        raise
+
+# Register all the executables in this directory as global functions.
+{0}
+"""
+
+
+def parse_dependencies_windows(data):
+    """ Parses the given output from dumpbin /dependents to determine the list
+    of dll's this executable file depends on. """
+
+    lines = data.splitlines()
+    li = 0
+    while li < len(lines):
+        line = lines[li]
+        li += 1
+        if line.find(' has the following dependencies') != -1:
+            break
+
+    if li < len(lines):
+        line = lines[li]
+        if line.strip() == '':
+            # Skip a blank line.
+            li += 1
+
+    # Now we're finding filenames, until the next blank line.
+    filenames = []
+    while li < len(lines):
+        line = lines[li]
+        li += 1
+        line = line.strip()
+        if line == '':
+            # We're done.
+            return filenames
+        filenames.append(line)
+
+    # At least we got some data.
+    return filenames
+
+
+def parse_dependencies_unix(data):
+    """ Parses the given output from otool -XL or ldd to determine the list of
+    libraries this executable file depends on. """
+
+    lines = data.splitlines()
+    filenames = []
+    for l in lines:
+        l = l.strip()
+        if l != "statically linked":
+            filenames.append(l.split(' ', 1)[0])
+    return filenames
+
+
+def scan_dependencies(pathname):
+    """ Checks the named file for DLL dependencies, and adds any appropriate
+    dependencies found into pluginDependencies and dependentFiles. """
+
+    if sys.platform == "darwin":
+        command = ['otool', '-XL', pathname]
+    elif sys.platform in ("win32", "cygwin"):
+        command = ['dumpbin', '/dependents', pathname]
+    else:
+        command = ['ldd', pathname]
+
+    process = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)
+    output, unused_err = process.communicate()
+    retcode = process.poll()
+    if retcode:
+        raise subprocess.CalledProcessError(retcode, command[0], output=output)
+    filenames = None
+
+    if sys.platform in ("win32", "cygwin"):
+        filenames = parse_dependencies_windows(output)
+    else:
+        filenames = parse_dependencies_unix(output)
+
+    if filenames is None:
+        sys.exit("Unable to determine dependencies from %s" % (pathname))
+
+    if sys.platform == "darwin" and len(filenames) > 0:
+        # Filter out the library ID.
+        if os.path.basename(filenames[0]).split('.', 1)[0] == os.path.basename(pathname).split('.', 1)[0]:
+            del filenames[0]
+
+    return filenames
+
+
+class WheelFile(object):
+    def __init__(self, name, version, platform):
+        self.name = name
+        self.version = version
+        self.platform = platform
+
+        wheel_name = "{0}-{1}-{2}-{3}-{4}.whl".format(
+            name, version, PY_VERSION, ABI_TAG, platform)
+
+        print("Writing %s" % (wheel_name))
+        self.zip_file = zipfile.ZipFile(wheel_name, 'w', zipfile.ZIP_DEFLATED)
+        self.records = []
+
+        # Used to locate dependency libraries.
+        self.lib_path = []
+        self.dep_paths = {}
+
+    def consider_add_dependency(self, target_path, dep, search_path=None):
+        """Considers adding a dependency library.
+        Returns the target_path if it was added, which may be different from
+        target_path if it was already added earlier, or None if it wasn't."""
+
+        if dep in self.dep_paths:
+            # Already considered this.
+            return self.dep_paths[dep]
+
+        self.dep_paths[dep] = None
+
+        if dep.lower().startswith("python") or os.path.basename(dep).startswith("libpython"):
+            # Don't include the Python library.
+            return
+
+        if sys.platform == "darwin" and dep.endswith(".so"):
+            # Temporary hack for 1.9, which had link deps on modules.
+            return
+
+        source_path = None
+
+        if search_path is None:
+            search_path = self.lib_path
+
+        for lib_dir in search_path:
+            # Ignore static stuff.
+            path = os.path.join(lib_dir, dep)
+            if os.path.isfile(path):
+                source_path = os.path.normpath(path)
+                break
+
+        if not source_path:
+            # Couldn't find library in the panda3d lib dir.
+            #print("Ignoring %s" % (dep))
+            return
+
+        self.dep_paths[dep] = target_path
+        self.write_file(target_path, source_path)
+        return target_path
+
+    def write_file(self, target_path, source_path):
+        """Adds the given file to the .whl file."""
+
+        # If this is a .so file, we should set the rpath appropriately.
+        temp = None
+        ext = os.path.splitext(source_path)[1]
+        if ext in ('.so', '.dylib') or '.so.' in os.path.basename(source_path) or \
+            (not ext and is_executable(source_path)):
+            # Scan and add Unix dependencies.
+            deps = scan_dependencies(source_path)
+            for dep in deps:
+                # Only include dependencies with relative path.  Otherwise we
+                # end up overwriting system files like /lib/ld-linux.so.2!
+                # Yes, it happened to me.
+                if '/' not in dep:
+                    target_dep = os.path.dirname(target_path) + '/' + dep
+                    self.consider_add_dependency(target_dep, dep)
+
+            suffix = ''
+            if '.so' in os.path.basename(source_path):
+                suffix = '.so'
+            elif ext == '.dylib':
+                suffix = '.dylib'
+
+            temp = tempfile.NamedTemporaryFile(suffix=suffix, prefix='whl', delete=False)
+
+            # On macOS, if no fat wheel was requested, extract the right architecture.
+            if sys.platform == "darwin" and is_fat_file(source_path) and not self.platform.endswith("_intel"):
+                if self.platform.endswith("_x86_64"):
+                    arch = 'x86_64'
+                else:
+                    arch = self.platform.split('_')[-1]
+                subprocess.call(['lipo', source_path, '-extract', arch, '-output', temp.name])
+            else:
+                # Otherwise, just copy it over.
+                temp.write(open(source_path, 'rb').read())
+
+            temp.write(open(source_path, 'rb').read())
+            os.fchmod(temp.fileno(), os.fstat(temp.fileno()).st_mode | 0o111)
+            temp.close()
+
+            # Fix things like @loader_path/../lib references
+            if sys.platform == "darwin":
+                loader_path = [os.path.dirname(source_path)]
+                for dep in deps:
+                    if '@loader_path' not in dep:
+                        continue
+
+                    dep_path = dep.replace('@loader_path', '.')
+                    target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep)
+                    target_dep = self.consider_add_dependency(target_dep, dep_path, loader_path)
+                    if not target_dep:
+                        # It won't be included, so no use adjusting the path.
+                        continue
+
+                    new_dep = os.path.join('@loader_path', os.path.relpath(target_dep, os.path.dirname(target_path)))
+                    subprocess.call(["install_name_tool", "-change", dep, new_dep, temp.name])
+            else:
+                subprocess.call(["strip", "-s", temp.name])
+                subprocess.call(["patchelf", "--set-rpath", "$ORIGIN", temp.name])
+
+            source_path = temp.name
+
+        ext = ext.lower()
+        if ext in ('.dll', '.pyd', '.exe'):
+            # Scan and add Win32 dependencies.
+            for dep in scan_dependencies(source_path):
+                target_dep = os.path.dirname(target_path) + '/' + dep
+                self.consider_add_dependency(target_dep, dep)
+
+        # Calculate the SHA-256 hash and size.
+        sha = hashlib.sha256()
+        fp = open(source_path, 'rb')
+        size = 0
+        data = fp.read(1024 * 1024)
+        while data:
+            size += len(data)
+            sha.update(data)
+            data = fp.read(1024 * 1024)
+        fp.close()
+
+        # Save it in PEP-0376 format for writing out later.
+        digest = str(urlsafe_b64encode(sha.digest()))
+        digest = digest.rstrip('=')
+        self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, size))
+
+        if GetVerbose():
+            print("Adding %s from %s" % (target_path, source_path))
+        self.zip_file.write(source_path, target_path)
+
+        #if temp:
+        #    os.unlink(temp.name)
+
+    def write_file_data(self, target_path, source_data):
+        """Adds the given file from a string."""
+
+        sha = hashlib.sha256()
+        sha.update(source_data.encode())
+        digest = str(urlsafe_b64encode(sha.digest()))
+        digest = digest.rstrip('=')
+        self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, len(source_data)))
+
+        if GetVerbose():
+            print("Adding %s from data" % target_path)
+        self.zip_file.writestr(target_path, source_data)
+
+    def write_directory(self, target_dir, source_dir):
+        """Adds the given directory recursively to the .whl file."""
+
+        for root, dirs, files in os.walk(source_dir):
+            for file in files:
+                if os.path.splitext(file)[1] in EXCLUDE_EXT:
+                    continue
+
+                source_path = os.path.join(root, file)
+                target_path = os.path.join(target_dir, os.path.relpath(source_path, source_dir))
+                target_path = target_path.replace('\\', '/')
+                self.write_file(target_path, source_path)
+
+    def close(self):
+        # Write the RECORD file.
+        record_file = "{0}-{1}.dist-info/RECORD".format(self.name, self.version)
+        self.records.append(record_file + ",,\n")
+
+        self.zip_file.writestr(record_file, "".join(self.records))
+        self.zip_file.close()
+
+
+def makewheel(version, output_dir, platform=default_platform):
+    if sys.platform not in ("win32", "darwin") and not sys.platform.startswith("cygwin"):
+        if not LocateBinary("patchelf"):
+            raise Exception("patchelf is required when building a Linux wheel.")
+
+    platform = platform.replace('-', '_').replace('.', '_')
+
+    # Global filepaths
+    panda3d_dir = join(output_dir, "panda3d")
+    pandac_dir = join(output_dir, "pandac")
+    direct_dir = join(output_dir, "direct")
+    models_dir = join(output_dir, "models")
+    etc_dir = join(output_dir, "etc")
+    bin_dir = join(output_dir, "bin")
+    if sys.platform == "win32":
+        libs_dir = join(output_dir, "bin")
+    else:
+        libs_dir = join(output_dir, "lib")
+    license_src = "LICENSE"
+    readme_src = "README.md"
+
+    # Update relevant METADATA entries
+    METADATA['version'] = version
+    version_classifiers = [
+        "Programming Language :: Python :: {0}".format(*sys.version_info),
+        "Programming Language :: Python :: {0}.{1}".format(*sys.version_info),
+    ]
+    METADATA['classifiers'].extend(version_classifiers)
+
+    # Build out the metadata
+    details = METADATA["extensions"]["python.details"]
+    homepage = details["project_urls"]["Home"]
+    author = details["contacts"][0]["name"]
+    email = details["contacts"][0]["email"]
+    metadata = ''.join([
+        "Metadata-Version: {metadata_version}\n" \
+        "Name: {name}\n" \
+        "Version: {version}\n" \
+        "Summary: {summary}\n" \
+        "License: {license}\n".format(**METADATA),
+        "Home-page: {0}\n".format(homepage),
+        "Author: {0}\n".format(author),
+        "Author-email: {0}\n".format(email),
+        "Platform: {0}\n".format(platform),
+    ] + ["Classifier: {0}\n".format(c) for c in METADATA['classifiers']])
+
+    # Zip it up and name it the right thing
+    whl = WheelFile('panda3d', version, platform)
+    whl.lib_path = [libs_dir]
+
+    # Add the trees with Python modules.
+    whl.write_directory('direct', direct_dir)
+
+    # Write the panda3d tree.  We use a custom empty __init__ since the
+    # default one adds the bin directory to the PATH, which we don't have.
+    whl.write_file_data('panda3d/__init__.py', '')
+
+    ext_suffix = GetExtensionSuffix()
+
+    for file in os.listdir(panda3d_dir):
+        if file == '__init__.py':
+            pass
+        elif file.endswith(ext_suffix) or file.endswith('.py'):
+            source_path = os.path.join(panda3d_dir, file)
+
+            if file.endswith('.pyd') and platform.startswith('cygwin'):
+                # Rename it to .dll for cygwin Python to be able to load it.
+                target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
+            else:
+                target_path = 'panda3d/' + file
+
+            whl.write_file(target_path, source_path)
+
+    # Add plug-ins.
+    for lib in PLUGIN_LIBS:
+        plugin_name = 'lib' + lib
+        if sys.platform in ('win32', 'cygwin'):
+            plugin_name += '.dll'
+        elif sys.platform == 'darwin':
+            plugin_name += '.dylib'
+        else:
+            plugin_name += '.so'
+        plugin_path = os.path.join(libs_dir, plugin_name)
+        if os.path.isfile(plugin_path):
+            whl.write_file('panda3d/' + plugin_name, plugin_path)
+
+    # Add the .data directory, containing additional files.
+    data_dir = 'panda3d-{0}.data'.format(version)
+    #whl.write_directory(data_dir + '/data/etc', etc_dir)
+    #whl.write_directory(data_dir + '/data/models', models_dir)
+
+    # Actually, let's not.  That seems to install the files to the strangest
+    # places in the user's filesystem.  Let's instead put them in panda3d.
+    whl.write_directory('panda3d/etc', etc_dir)
+    whl.write_directory('panda3d/models', models_dir)
+
+    # Add the pandac tree for backward compatibility.
+    for file in os.listdir(pandac_dir):
+        if file.endswith('.py'):
+            whl.write_file('pandac/' + file, os.path.join(pandac_dir, file))
+
+    # Add a panda3d-tools directory containing the executables.
+    entry_points = '[console_scripts]\n'
+    entry_points += 'eggcacher = direct.directscripts.eggcacher:main\n'
+    entry_points += 'packpanda = direct.directscripts.packpanda:main\n'
+    tools_init = ''
+    for file in os.listdir(bin_dir):
+        basename = os.path.splitext(file)[0]
+        if basename in ('eggcacher', 'packpanda'):
+            continue
+
+        source_path = os.path.join(bin_dir, file)
+
+        if is_executable(source_path):
+            # Put the .exe files inside the panda3d-tools directory.
+            whl.write_file('panda3d_tools/' + file, source_path)
+
+            # Tell pip to create a wrapper script.
+            funcname = basename.replace('-', '_')
+            entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
+            tools_init += '{0} = lambda: _exec_tool({1!r})\n'.format(funcname, file)
+
+    whl.write_file_data('panda3d_tools/__init__.py', PANDA3D_TOOLS_INIT.format(tools_init))
+
+    # Add the dist-info directory last.
+    info_dir = 'panda3d-{0}.dist-info'.format(version)
+    whl.write_file_data(info_dir + '/entry_points.txt', entry_points)
+    whl.write_file_data(info_dir + '/metadata.json', json.dumps(METADATA, indent=4, separators=(',', ': ')))
+    whl.write_file_data(info_dir + '/METADATA', metadata)
+    whl.write_file_data(info_dir + '/WHEEL', WHEEL_DATA.format(PY_VERSION, ABI_TAG, platform))
+    whl.write_file(info_dir + '/LICENSE.txt', license_src)
+    whl.write_file(info_dir + '/README.md', readme_src)
+    whl.write_file_data(info_dir + '/top_level.txt', 'direct\npanda3d\npandac\npanda3d_tools\n')
+
+    whl.close()
+
+
+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('', '--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('', '--platform', dest = 'platform', help = 'Override platform tag (default: %s)' % (default_platform), default = get_platform())
+    (options, args) = parser.parse_args()
+
+    SetVerbose(options.verbose)
+    makewheel(options.version, options.outputdir, options.platform)

+ 0 - 8
panda/.gitignore

@@ -1,8 +0,0 @@
-*.pyc
-*.pyo
-# These are files that are generated within the source tree by the
-# ppremake system.
-Makefile
-pp.dep
-/built/
-Opt?-*

+ 1 - 1
panda/src/audiotraits/openalAudioManager.h

@@ -23,7 +23,7 @@
 #include "reMutex.h"
 #include "reMutex.h"
 
 
 // OSX uses the OpenAL framework
 // OSX uses the OpenAL framework
-#ifdef IS_OSX
+#ifdef HAVE_OPENAL_FRAMEWORK
   #include <OpenAL/al.h>
   #include <OpenAL/al.h>
   #include <OpenAL/alc.h>
   #include <OpenAL/alc.h>
 #else
 #else

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

@@ -21,7 +21,7 @@
 #include "openalAudioManager.h"
 #include "openalAudioManager.h"
 
 
 // OSX uses the OpenAL framework
 // OSX uses the OpenAL framework
-#ifdef IS_OSX
+#ifdef HAVE_OPENAL_FRAMEWORK
   #include <OpenAL/al.h>
   #include <OpenAL/al.h>
   #include <OpenAL/alc.h>
   #include <OpenAL/alc.h>
 #else
 #else

+ 28 - 0
panda/src/bullet/bulletBodyNode.cxx

@@ -36,6 +36,34 @@ BulletBodyNode(const char *name) : PandaNode(name) {
   set_into_collide_mask(CollideMask::all_on());
   set_into_collide_mask(CollideMask::all_on());
 }
 }
 
 
+/**
+ *
+ */
+BulletBodyNode::
+BulletBodyNode(const BulletBodyNode &copy) :
+  PandaNode(copy),
+  _shapes(copy._shapes)
+{
+  if (copy._shape && copy._shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) {
+    // btCompoundShape does not define a copy constructor.  Manually copy.
+    btCompoundShape *shape = new btCompoundShape;
+    _shape = shape;
+
+    btCompoundShape *copy_shape = (btCompoundShape *)copy._shape;
+    int num_children = copy_shape->getNumChildShapes();
+    for (int i = 0; i < num_children; ++i) {
+      shape->addChildShape(copy_shape->getChildTransform(i),
+                           copy_shape->getChildShape(i));
+    }
+  }
+  else if (copy._shape && copy._shape->getShapeType() == EMPTY_SHAPE_PROXYTYPE) {
+    _shape = new btEmptyShape();
+  }
+  else {
+    _shape = copy._shape;
+  }
+}
+
 /**
 /**
  * Returns the subset of CollideMask bits that may be set for this particular
  * Returns the subset of CollideMask bits that may be set for this particular
  * type of PandaNode.  For BodyNodes this returns all bits on.
  * type of PandaNode.  For BodyNodes this returns all bits on.

Some files were not shown because too many files changed in this diff