Browse Source

Merge remote-tracking branch 'origin/master' into vulkan

rdb 9 years ago
parent
commit
731d0eb1dd
100 changed files with 1602 additions and 1080 deletions
  1. 9 4
      .gitignore
  2. 1 1
      direct/src/controls/BattleWalker.py
  3. 1 1
      direct/src/controls/NonPhysicsWalker.py
  4. 1 1
      direct/src/distributed/CartesianGridBase.py
  5. 2 1
      direct/src/distributed/ClientRepositoryBase.py
  6. 2 1
      direct/src/distributed/ConnectionRepository.py
  7. 2 1
      direct/src/distributed/DistributedCamera.py
  8. 2 1
      direct/src/distributed/DistributedCameraOV.py
  9. 2 1
      direct/src/distributed/DistributedCartesianGrid.py
  10. 2 1
      direct/src/distributed/DistributedCartesianGridAI.py
  11. 1 1
      direct/src/distributed/DistributedNodeAI.py
  12. 5 1
      direct/src/distributed/DistributedObjectGlobalUD.py
  13. 2 1
      direct/src/distributed/DistributedObjectUD.py
  14. 2 1
      direct/src/distributed/DistributedSmoothNode.py
  15. 2 1
      direct/src/distributed/DoInterestManager.py
  16. 2 1
      direct/src/distributed/GridParent.py
  17. 2 1
      direct/src/distributed/ServerRepository.py
  18. 1 1
      direct/src/distributed/TimeManager.py
  19. 1 1
      direct/src/distributed/TimeManagerAI.py
  20. 10 10
      direct/src/fsm/FSM.py
  21. 1 0
      direct/src/p3d/Packager.py
  22. 6 1
      direct/src/p3d/SeqValue.py
  23. 8 3
      direct/src/p3d/panda3d.pdef
  24. 18 0
      direct/src/plugin/p3dPythonRun.cxx
  25. 10 6
      direct/src/showbase/DistancePhasedNode.py
  26. 1 0
      direct/src/showbase/ExceptionVarDump.py
  27. 1 1
      direct/src/showbase/LeakDetectors.py
  28. 1 1
      direct/src/showbase/MirrorDemo.py
  29. 1 1
      direct/src/showbase/ShadowDemo.py
  30. 1 1
      direct/src/showbase/ShadowPlacer.py
  31. 22 5
      direct/src/showbase/ShowBase.py
  32. 2 4
      direct/src/showbase/VFSImporter.py
  33. 1 1
      direct/src/showutil/FreezeTool.py
  34. 3 3
      direct/src/tkpanels/ParticlePanel.py
  35. 20 0
      doc/ReleaseNotes
  36. 148 148
      dtool/src/cppparser/cppBison.cxx.prebuilt
  37. 1 1
      dtool/src/cppparser/cppBison.yxx
  38. 1 0
      dtool/src/cppparser/cppEnumType.h
  39. 62 28
      dtool/src/cppparser/cppScope.cxx
  40. 2 0
      dtool/src/cppparser/cppScope.h
  41. 1 1
      dtool/src/cppparser/cppStructType.cxx
  42. 10 0
      dtool/src/cppparser/cppTemplateScope.cxx
  43. 2 0
      dtool/src/cppparser/cppTemplateScope.h
  44. 17 0
      dtool/src/cppparser/cppTypedefType.cxx
  45. 8 1
      dtool/src/cppparser/cppTypedefType.h
  46. 0 534
      dtool/src/dtoolbase/dlmalloc.h
  47. 405 130
      dtool/src/dtoolbase/dlmalloc_src.cxx
  48. 0 1
      dtool/src/dtoolbase/dtoolbase.h
  49. 7 4
      dtool/src/dtoolbase/memoryHook.cxx
  50. 1 1
      dtool/src/dtoolbase/pallocator.h
  51. 1 1
      dtool/src/dtoolbase/pdeque.h
  52. 1 1
      dtool/src/dtoolbase/pdtoa.cxx
  53. 1 1
      dtool/src/dtoolbase/plist.h
  54. 1 1
      dtool/src/dtoolbase/pmap.h
  55. 1 1
      dtool/src/dtoolbase/pset.h
  56. 6 0
      dtool/src/dtoolbase/pvector.h
  57. 5 1
      dtool/src/dtoolutil/filename.cxx
  58. 14 1
      dtool/src/interrogate/interfaceMaker.cxx
  59. 29 4
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  60. 4 2
      dtool/src/interrogate/interrogateBuilder.cxx
  61. 60 0
      dtool/src/interrogate/typeManager.cxx
  62. 2 0
      dtool/src/interrogate/typeManager.h
  63. 4 0
      dtool/src/interrogatedb/interrogate_request.cxx
  64. 2 4
      dtool/src/interrogatedb/py_panda.cxx
  65. 7 0
      dtool/src/interrogatedb/py_panda.h
  66. 17 0
      dtool/src/parser-inc/netinet/in.h
  67. 0 10
      dtool/src/parser-inc/socket.h
  68. 18 0
      dtool/src/parser-inc/sys/socket.h
  69. 3 0
      dtool/src/parser-inc/winsock2.h
  70. 1 0
      dtool/src/parser-inc/ws2tcpip.h
  71. 7 2
      dtool/src/prc/notifyCategory.cxx
  72. 12 8
      makepanda/makepanda.py
  73. 21 14
      makepanda/makepandacore.py
  74. 2 2
      panda/src/audio/audioManager.cxx
  75. 20 0
      panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm
  76. 20 0
      panda/src/cocoadisplay/cocoaPandaApp.mm
  77. 9 0
      panda/src/display/config_display.cxx
  78. 1 0
      panda/src/display/config_display.h
  79. 3 0
      panda/src/display/graphicsEngine.cxx
  80. 2 2
      panda/src/display/graphicsEngine.h
  81. 8 0
      panda/src/downloader/bioPtr.I
  82. 167 5
      panda/src/downloader/bioPtr.cxx
  83. 16 0
      panda/src/downloader/bioPtr.h
  84. 6 0
      panda/src/downloader/config_downloader.cxx
  85. 1 0
      panda/src/downloader/config_downloader.h
  86. 41 18
      panda/src/downloader/httpChannel.cxx
  87. 3 2
      panda/src/downloader/httpDate.cxx
  88. 5 13
      panda/src/downloader/multiplexStreamBuf.cxx
  89. 2 0
      panda/src/downloader/multiplexStreamBuf.h
  90. 26 24
      panda/src/downloader/urlSpec.I
  91. 166 34
      panda/src/downloader/urlSpec.cxx
  92. 21 7
      panda/src/downloader/urlSpec.h
  93. 11 1
      panda/src/downloadertools/multify.cxx
  94. 8 1
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  95. 8 0
      panda/src/dxml/config_dxml.cxx
  96. 1 1
      panda/src/egg/eggCompositePrimitive.h
  97. 10 10
      panda/src/egg2pg/eggBinner.cxx
  98. 1 1
      panda/src/egg2pg/eggLoader.cxx
  99. 4 0
      panda/src/event/pythonTask.cxx
  100. 10 0
      panda/src/express/hashVal.I

+ 9 - 4
.gitignore

@@ -1,4 +1,9 @@
-/built_x64
-/built
-/thirdparty
-/targetroot
+/built*/
+/thirdparty/
+/targetroot/
+/dstroot/
+core
+core.*
+vgcore.*
+*.save
+*.save.1

+ 1 - 1
direct/src/controls/BattleWalker.py

@@ -1,7 +1,7 @@
 
 
 from direct.showbase.InputStateGlobal import inputState
 from direct.showbase.InputStateGlobal import inputState
 from direct.task.Task import Task
 from direct.task.Task import Task
-from pandac.PandaModules import *
+from panda3d.core import *
 from . import GravityWalker
 from . import GravityWalker
 
 
 BattleStrafe = 0
 BattleStrafe = 0

+ 1 - 1
direct/src/controls/NonPhysicsWalker.py

@@ -19,7 +19,7 @@ from direct.showbase import DirectObject
 from direct.controls.ControlManager import CollisionHandlerRayStart
 from direct.controls.ControlManager import CollisionHandlerRayStart
 from direct.showbase.InputStateGlobal import inputState
 from direct.showbase.InputStateGlobal import inputState
 from direct.task.Task import Task
 from direct.task.Task import Task
-from pandac.PandaModules import *
+from panda3d.core import *
 
 
 class NonPhysicsWalker(DirectObject.DirectObject):
 class NonPhysicsWalker(DirectObject.DirectObject):
     notify = DirectNotifyGlobal.directNotify.newCategory("NonPhysicsWalker")
     notify = DirectNotifyGlobal.directNotify.newCategory("NonPhysicsWalker")

+ 1 - 1
direct/src/distributed/CartesianGridBase.py

@@ -1,4 +1,4 @@
-from pandac.PandaModules import Vec3
+from panda3d.core import Vec3
 # Utility functions that are useful to both AI and client CartesianGrid code
 # Utility functions that are useful to both AI and client CartesianGrid code
 
 
 class CartesianGridBase:
 class CartesianGridBase:

+ 2 - 1
direct/src/distributed/ClientRepositoryBase.py

@@ -1,4 +1,5 @@
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from .MsgTypes import *
 from .MsgTypes import *
 from direct.task import Task
 from direct.task import Task
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal

+ 2 - 1
direct/src/distributed/ConnectionRepository.py

@@ -1,4 +1,5 @@
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.task import Task
 from direct.task import Task
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.distributed.DoInterestManager import DoInterestManager
 from direct.distributed.DoInterestManager import DoInterestManager

+ 2 - 1
direct/src/distributed/DistributedCamera.py

@@ -1,4 +1,5 @@
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.fsm.FSM import FSM
 from direct.fsm.FSM import FSM
 from direct.interval.IntervalGlobal import *
 from direct.interval.IntervalGlobal import *
 from direct.distributed.DistributedObject import DistributedObject
 from direct.distributed.DistributedObject import DistributedObject

+ 2 - 1
direct/src/distributed/DistributedCameraOV.py

@@ -1,4 +1,5 @@
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.distributed.DistributedObjectOV import DistributedObjectOV
 from direct.distributed.DistributedObjectOV import DistributedObjectOV
 
 
 class DistributedCameraOV(DistributedObjectOV):
 class DistributedCameraOV(DistributedObjectOV):

+ 2 - 1
direct/src/distributed/DistributedCartesianGrid.py

@@ -1,5 +1,6 @@
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.interval.IntervalGlobal import *
 from direct.interval.IntervalGlobal import *
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 
 

+ 2 - 1
direct/src/distributed/DistributedCartesianGridAI.py

@@ -1,5 +1,6 @@
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.task import Task
 from direct.task import Task
 from .DistributedNodeAI import DistributedNodeAI
 from .DistributedNodeAI import DistributedNodeAI

+ 1 - 1
direct/src/distributed/DistributedNodeAI.py

@@ -1,4 +1,4 @@
-from pandac.PandaModules import NodePath
+from panda3d.core import NodePath
 from . import DistributedObjectAI
 from . import DistributedObjectAI
 from . import GridParent
 from . import GridParent
 
 

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

@@ -35,7 +35,11 @@ class DistributedObjectGlobalUD(DistributedObjectUD):
     def __execMessage(self, message):
     def __execMessage(self, message):
         if not self.ExecNamespace:
         if not self.ExecNamespace:
             # Import some useful variables into the ExecNamespace initially.
             # Import some useful variables into the ExecNamespace initially.
-            exec('from pandac.PandaModules import *', globals(), self.ExecNamespace)
+            import panda3d.core
+
+            for key, value in panda3d.core.__dict__.items():
+                if not key.startswith('__'):
+                    self.ExecNamespace[key] = value
             #self.importExecNamespace()
             #self.importExecNamespace()
 
 
         # Now try to evaluate the expression using ChatInputNormal.ExecNamespace as
         # Now try to evaluate the expression using ChatInputNormal.ExecNamespace as

+ 2 - 1
direct/src/distributed/DistributedObjectUD.py

@@ -3,7 +3,8 @@
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.distributed.DistributedObjectBase import DistributedObjectBase
 from direct.distributed.DistributedObjectBase import DistributedObjectBase
 from direct.showbase import PythonUtil
 from direct.showbase import PythonUtil
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 #from PyDatagram import PyDatagram
 #from PyDatagram import PyDatagram
 #from PyDatagramIterator import PyDatagramIterator
 #from PyDatagramIterator import PyDatagramIterator
 
 

+ 2 - 1
direct/src/distributed/DistributedSmoothNode.py

@@ -1,6 +1,7 @@
 """DistributedSmoothNode module: contains the DistributedSmoothNode class"""
 """DistributedSmoothNode module: contains the DistributedSmoothNode class"""
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from .ClockDelta import *
 from .ClockDelta import *
 from . import DistributedNode
 from . import DistributedNode
 from . import DistributedSmoothNodeBase
 from . import DistributedSmoothNodeBase

+ 2 - 1
direct/src/distributed/DoInterestManager.py

@@ -7,7 +7,8 @@ zone, remove interest in that zone.
 p.s. A great deal of this code is just code moved from ClientRepository.py.
 p.s. A great deal of this code is just code moved from ClientRepository.py.
 """
 """
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from .MsgTypes import *
 from .MsgTypes import *
 from direct.showbase.PythonUtil import *
 from direct.showbase.PythonUtil import *
 from direct.showbase import DirectObject
 from direct.showbase import DirectObject

+ 2 - 1
direct/src/distributed/GridParent.py

@@ -1,5 +1,6 @@
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 
 
 #
 #
 # GridParent.py
 # GridParent.py

+ 2 - 1
direct/src/distributed/ServerRepository.py

@@ -1,6 +1,7 @@
 """ServerRepository module: contains the ServerRepository class"""
 """ServerRepository module: contains the ServerRepository class"""
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from direct.distributed.MsgTypesCMU import *
 from direct.distributed.MsgTypesCMU import *
 from direct.task import Task
 from direct.task import Task
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal

+ 1 - 1
direct/src/distributed/TimeManager.py

@@ -1,5 +1,5 @@
 from direct.showbase.DirectObject import *
 from direct.showbase.DirectObject import *
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.task import Task
 from direct.task import Task
 from direct.distributed import DistributedObject
 from direct.distributed import DistributedObject
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal

+ 1 - 1
direct/src/distributed/TimeManagerAI.py

@@ -1,5 +1,5 @@
 from direct.distributed.ClockDelta import *
 from direct.distributed.ClockDelta import *
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.distributed import DistributedObjectAI
 from direct.distributed import DistributedObjectAI
 
 
 class TimeManagerAI(DistributedObjectAI.DistributedObjectAI):
 class TimeManagerAI(DistributedObjectAI.DistributedObjectAI):

+ 10 - 10
direct/src/fsm/FSM.py

@@ -149,7 +149,7 @@ class FSM(DirectObject):
 
 
     def __init__(self, name):
     def __init__(self, name):
         self.fsmLock = RLock()
         self.fsmLock = RLock()
-        self.name = name
+        self._name = name
         self.stateArray = []
         self.stateArray = []
         self._serialNum = FSM.SerialNum
         self._serialNum = FSM.SerialNum
         FSM.SerialNum += 1
         FSM.SerialNum += 1
@@ -185,7 +185,7 @@ class FSM(DirectObject):
         # the messenger on every state change. The new and old states are
         # the messenger on every state change. The new and old states are
         # accessible as self.oldState and self.newState, and the transition
         # accessible as self.oldState and self.newState, and the transition
         # functions will already have been called.
         # functions will already have been called.
-        return 'FSM-%s-%s-stateChange' % (self._serialNum, self.name)
+        return 'FSM-%s-%s-stateChange' % (self._serialNum, self._name)
 
 
     def getCurrentFilter(self):
     def getCurrentFilter(self):
         if not self.state:
         if not self.state:
@@ -240,7 +240,7 @@ class FSM(DirectObject):
         try:
         try:
             assert isinstance(request, str)
             assert isinstance(request, str)
             self.notify.debug("%s.forceTransition(%s, %s" % (
             self.notify.debug("%s.forceTransition(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
 
 
             if not self.state:
             if not self.state:
                 # Queue up the request.
                 # Queue up the request.
@@ -268,7 +268,7 @@ class FSM(DirectObject):
         try:
         try:
             assert isinstance(request, str)
             assert isinstance(request, str)
             self.notify.debug("%s.demand(%s, %s" % (
             self.notify.debug("%s.demand(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
             if not self.state:
             if not self.state:
                 # Queue up the request.
                 # Queue up the request.
                 self.__requestQueue.append(PythonUtil.Functor(
                 self.__requestQueue.append(PythonUtil.Functor(
@@ -307,7 +307,7 @@ class FSM(DirectObject):
         try:
         try:
             assert isinstance(request, str)
             assert isinstance(request, str)
             self.notify.debug("%s.request(%s, %s" % (
             self.notify.debug("%s.request(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
 
 
             filter = self.getCurrentFilter()
             filter = self.getCurrentFilter()
             result = filter(request, args)
             result = filter(request, args)
@@ -385,7 +385,7 @@ class FSM(DirectObject):
 
 
         # In either case, we quietly ignore unhandled command
         # In either case, we quietly ignore unhandled command
         # (lowercase) requests.
         # (lowercase) requests.
-        assert self.notify.debug("%s ignoring request %s from state %s." % (self.name, request, self.state))
+        assert self.notify.debug("%s ignoring request %s from state %s." % (self._name, request, self.state))
         return None
         return None
 
 
     def filterOff(self, request, args):
     def filterOff(self, request, args):
@@ -444,7 +444,7 @@ class FSM(DirectObject):
         # Internal function to change unconditionally to the indicated
         # Internal function to change unconditionally to the indicated
         # state.
         # state.
         assert self.state
         assert self.state
-        assert self.notify.debug("%s to state %s." % (self.name, newState))
+        assert self.notify.debug("%s to state %s." % (self._name, newState))
 
 
         self.oldState = self.state
         self.oldState = self.state
         self.newState = newState
         self.newState = newState
@@ -476,7 +476,7 @@ class FSM(DirectObject):
 
 
         if self.__requestQueue:
         if self.__requestQueue:
             request = self.__requestQueue.pop(0)
             request = self.__requestQueue.pop(0)
-            assert self.notify.debug("%s continued queued request." % (self.name))
+            assert self.notify.debug("%s continued queued request." % (self._name))
             request()
             request()
 
 
     def __callEnterFunc(self, name, *args):
     def __callEnterFunc(self, name, *args):
@@ -525,9 +525,9 @@ class FSM(DirectObject):
         try:
         try:
             className = self.__class__.__name__
             className = self.__class__.__name__
             if self.state:
             if self.state:
-                str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
+                str = ('%s FSM:%s in state "%s"' % (className, self._name, self.state))
             else:
             else:
-                str = ('%s FSM:%s in transition from \'%s\' to \'%s\'' % (className, self.name, self.oldState, self.newState))
+                str = ('%s FSM:%s in transition from \'%s\' to \'%s\'' % (className, self._name, self.oldState, self.newState))
             return str
             return str
         finally:
         finally:
             self.fsmLock.release()
             self.fsmLock.release()

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

@@ -2484,6 +2484,7 @@ class Packager:
             GlobPattern('libthr.so*'),
             GlobPattern('libthr.so*'),
             GlobPattern('ld-linux.so*'),
             GlobPattern('ld-linux.so*'),
             GlobPattern('ld-linux-*.so*'),
             GlobPattern('ld-linux-*.so*'),
+            GlobPattern('librt.so*'),
             ]
             ]
 
 
         # A Loader for loading models.
         # A Loader for loading models.

+ 6 - 1
direct/src/p3d/SeqValue.py

@@ -77,9 +77,14 @@ class SeqValue:
         """ Compares to another seq value. """
         """ Compares to another seq value. """
         return cmp(self.value, other.value)
         return cmp(self.value, other.value)
 
 
+    def __lt__(self, other):
+        return self.value < other.value
+
+    def __gt__(self, other):
+        return self.value > other.value
+
     def __bool__(self):
     def __bool__(self):
         return bool(self.value)
         return bool(self.value)
 
 
     def __str__(self):
     def __str__(self):
         return 'SeqValue%s' % (repr(self.value))
         return 'SeqValue%s' % (repr(self.value))
-

+ 8 - 3
direct/src/p3d/panda3d.pdef

@@ -63,8 +63,10 @@ class panda3d(package):
 
 
     # Include various standard Python encodings.  The rest is in morepy.
     # Include various standard Python encodings.  The rest is in morepy.
     module('encodings', 'encodings.aliases', 'encodings.undefined',
     module('encodings', 'encodings.aliases', 'encodings.undefined',
-           'encodings.utf_8', 'encodings.ascii', 'encodings.string_escape',
-           'encodings.mbcs', 'encodings.latin_1', 'io')
+           'encodings.utf_8', 'encodings.ascii', 'encodings.mbcs',
+           'encodings.latin_1', 'io')
+    if sys.version_info < (3, 0):
+        module('encodings.string_escape')
 
 
     # Pick up the shader files that appear in direct/src/filter.
     # Pick up the shader files that appear in direct/src/filter.
     import direct
     import direct
@@ -241,7 +243,10 @@ class models(package):
     # we assume this is the models directory.
     # we assume this is the models directory.
     pathname = getModelPath().findFile('cmss12.egg')
     pathname = getModelPath().findFile('cmss12.egg')
     if pathname:
     if pathname:
-        dir(pathname.getDirname(), newDir = '')
+        dir(pathname.getDirname(), newDir = 'models')
+
+    # Some people are used to loading the models without models/ prefix.
+    file('models.prc', extract = True, text = "model-path $MODELS_ROOT/models")
 
 
 
 
 class fmod(package):
 class fmod(package):

+ 18 - 0
direct/src/plugin/p3dPythonRun.cxx

@@ -217,6 +217,24 @@ run_python() {
     PyModule_AddStringConstant(showbase_module, "__package__", "direct.showbase");
     PyModule_AddStringConstant(showbase_module, "__package__", "direct.showbase");
   }
   }
 
 
+  PyObject *stdpy_module = PyImport_AddModule("direct.stdpy");
+  if (stdpy_module != NULL) {
+    Filename stdpy_dir(direct_dir, "stdpy");
+    dir_str = stdpy_dir.to_os_specific();
+    PyModule_AddObject(stdpy_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length()));
+    PyModule_AddStringConstant(stdpy_module, "__package__", "direct.stdpy");
+  }
+
+  // And the encodings package as well, since we've presumably picked up a
+  // bunch of encodings modules as part of the frozen bundle.
+  Filename encodings_dir(dir, "encodings");
+  PyObject *encodings_module = PyImport_AddModule("encodings");
+  if (encodings_module != NULL) {
+    dir_str = encodings_dir.to_os_specific();
+    PyModule_AddObject(encodings_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length()));
+    PyModule_AddStringConstant(encodings_module, "__package__", "encodings");
+  }
+
   // And register the VFSImporter.
   // And register the VFSImporter.
   PyObject *result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
   PyObject *result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
   if (result == NULL) {
   if (result == NULL) {

+ 10 - 6
direct/src/showbase/DistancePhasedNode.py

@@ -106,10 +106,12 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
 
 
     def __repr__(self):
     def __repr__(self):
         outStr = 'DistancePhasedObject('
         outStr = 'DistancePhasedObject('
-        outStr += '%s' % repr(self.getName())
+        outStr += repr(self.getName())
         for param, value in zip(('phaseParamMap', 'autoCleanup', 'enterPrefix', 'exitPrefix', 'phaseCollideMask', 'fromCollideNode'),
         for param, value in zip(('phaseParamMap', 'autoCleanup', 'enterPrefix', 'exitPrefix', 'phaseCollideMask', 'fromCollideNode'),
-                                ('{}', 'True','\'enter\'','\'exit\'','BitMask32.allOn()','None')):
-            outStr += eval('(\', ' + param + ' = %s\' % repr(self.' + param + '),\'\')[self.' + param + ' == ' + value + ']')
+                                ({}, True, 'enter', 'exit', BitMask32.allOn(), None)):
+            pv = getattr(self, param)
+            if pv != value:
+                outStr += ', %s = %r' % (param, pv)
         outStr += ')'
         outStr += ')'
         return outStr
         return outStr
 
 
@@ -287,10 +289,12 @@ class BufferedDistancePhasedNode(DistancePhasedNode):
 
 
     def __repr__(self):
     def __repr__(self):
         outStr = 'BufferedDistancePhasedNode('
         outStr = 'BufferedDistancePhasedNode('
-        outStr += '%s' % repr(self.getName())
+        outStr += repr(self.getName())
         for param, value in zip(('bufferParamMap', 'autoCleanup', 'enterPrefix', 'exitPrefix', 'phaseCollideMask', 'fromCollideNode'),
         for param, value in zip(('bufferParamMap', 'autoCleanup', 'enterPrefix', 'exitPrefix', 'phaseCollideMask', 'fromCollideNode'),
-                                ('{}', 'True','\'enter\'','\'exit\'','BitMask32.allOn()', 'None')):
-            outStr += eval('(\', ' + param + ' = %s\' % repr(self.' + param + '),\'\')[self.' + param + ' == ' + value + ']')
+                                ({}, True, 'enter', 'exit', BitMask32.allOn(), None)):
+            pv = getattr(self, param)
+            if pv != value:
+                outStr += ', %s = %r' % (param, pv)
         outStr += ')'
         outStr += ')'
         return outStr
         return outStr
 
 

+ 1 - 0
direct/src/showbase/ExceptionVarDump.py

@@ -1,5 +1,6 @@
 __all__ = ["install"]
 __all__ = ["install"]
 
 
+from panda3d.core import *
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import fastRepr
 from direct.showbase.PythonUtil import fastRepr
 import sys
 import sys

+ 1 - 1
direct/src/showbase/LeakDetectors.py

@@ -1,6 +1,6 @@
 # objects that report different types of leaks to the ContainerLeakDetector
 # objects that report different types of leaks to the ContainerLeakDetector
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.DirectObject import DirectObject
 from direct.showbase.Job import Job
 from direct.showbase.Job import Job
 import gc, sys
 import gc, sys

+ 1 - 1
direct/src/showbase/MirrorDemo.py

@@ -23,7 +23,7 @@ surface are possible, like a funhouse mirror.  However, the reflection
 itself is always basically planar; for more accurate convex
 itself is always basically planar; for more accurate convex
 reflections, you will need to use a sphere map or a cube map."""
 reflections, you will need to use a sphere map or a cube map."""
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.task import Task
 from direct.task import Task
 
 
 def setupMirror(name, width, height, rootCamera = None):
 def setupMirror(name, width, height, rootCamera = None):

+ 1 - 1
direct/src/showbase/ShadowDemo.py

@@ -14,7 +14,7 @@ multitexture rendering techniques.  It's not a particularly great
 way to do shadows.
 way to do shadows.
 """
 """
 
 
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.task import Task
 from direct.task import Task
 
 
 sc = None
 sc = None

+ 1 - 1
direct/src/showbase/ShadowPlacer.py

@@ -12,7 +12,7 @@ the its parent node.
 
 
 from direct.controls.ControlManager import CollisionHandlerRayStart
 from direct.controls.ControlManager import CollisionHandlerRayStart
 from direct.directnotify import DirectNotifyGlobal
 from direct.directnotify import DirectNotifyGlobal
-from pandac.PandaModules import *
+from panda3d.core import *
 from . import DirectObject
 from . import DirectObject
 
 
 class ShadowPlacer(DirectObject.DirectObject):
 class ShadowPlacer(DirectObject.DirectObject):

+ 22 - 5
direct/src/showbase/ShowBase.py

@@ -201,7 +201,9 @@ class ShowBase(DirectObject.DirectObject):
         ## This is used to store the wx.Application object used when want-wx is
         ## This is used to store the wx.Application object used when want-wx is
         ## set or base.startWx() is called.
         ## set or base.startWx() is called.
         self.wxApp = None
         self.wxApp = None
+        self.wxAppCreated = False
         self.tkRoot = None
         self.tkRoot = None
+        self.tkRootCreated = False
 
 
         # This is used for syncing multiple PCs in a distributed cluster
         # This is used for syncing multiple PCs in a distributed cluster
         try:
         try:
@@ -259,6 +261,17 @@ class ShowBase(DirectObject.DirectObject):
             random.seed(seed)
             random.seed(seed)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
 
 
+        # For some reason, wx needs to be initialized before the graphics window
+        if sys.platform == "darwin":
+            if self.config.GetBool("want-wx", 0):
+                wx = importlib.import_module('wx')
+                self.wxApp = wx.App()
+
+            # Same goes for Tk, which uses a conflicting NSApplication
+            if self.config.GetBool("want-tk", 0):
+                Pmw = importlib.import_module('Pmw')
+                self.tkRoot = Pmw.initialise()
+
         # Open the default rendering window.
         # Open the default rendering window.
         if self.windowType != 'none':
         if self.windowType != 'none':
             props = WindowProperties.getDefault()
             props = WindowProperties.getDefault()
@@ -2821,7 +2834,7 @@ class ShowBase(DirectObject.DirectObject):
         updated, but wxPython owns the main loop (which seems to make
         updated, but wxPython owns the main loop (which seems to make
         it happier than the other way around). """
         it happier than the other way around). """
 
 
-        if self.wxApp:
+        if self.wxAppCreated:
             # Don't do this twice.
             # Don't do this twice.
             return
             return
 
 
@@ -2831,8 +2844,9 @@ class ShowBase(DirectObject.DirectObject):
         # by modulefinder when packaging an application.
         # by modulefinder when packaging an application.
         wx = importlib.import_module('wx')
         wx = importlib.import_module('wx')
 
 
-        # Create a new base.wxApp.
-        self.wxApp = wx.PySimpleApp(redirect = False)
+        if not self.wxApp:
+            # Create a new base.wxApp.
+            self.wxApp = wx.PySimpleApp(redirect = False)
 
 
         if ConfigVariableBool('wx-main-loop', True):
         if ConfigVariableBool('wx-main-loop', True):
             # Put wxPython in charge of the main loop.  It really
             # Put wxPython in charge of the main loop.  It really
@@ -2867,6 +2881,7 @@ class ShowBase(DirectObject.DirectObject):
                 return task.again
                 return task.again
 
 
             self.taskMgr.add(wxLoop, 'wxLoop')
             self.taskMgr.add(wxLoop, 'wxLoop')
+        self.wxAppCreated = True
 
 
     def __wxTimerCallback(self, event):
     def __wxTimerCallback(self, event):
         if Thread.getCurrentThread().getCurrentTask():
         if Thread.getCurrentThread().getCurrentTask():
@@ -2901,7 +2916,7 @@ class ShowBase(DirectObject.DirectObject):
         updated, but Tkinter owns the main loop (which seems to make
         updated, but Tkinter owns the main loop (which seems to make
         it happier than the other way around). """
         it happier than the other way around). """
 
 
-        if self.tkRoot:
+        if self.tkRootCreated:
             # Don't do this twice.
             # Don't do this twice.
             return
             return
 
 
@@ -2911,7 +2926,8 @@ class ShowBase(DirectObject.DirectObject):
         Pmw = importlib.import_module('Pmw')
         Pmw = importlib.import_module('Pmw')
 
 
         # Create a new Tk root.
         # Create a new Tk root.
-        self.tkRoot = Pmw.initialise()
+        if not self.tkRoot:
+            self.tkRoot = Pmw.initialise()
         builtins.tkroot = self.tkRoot
         builtins.tkroot = self.tkRoot
 
 
         init_app_for_gui()
         init_app_for_gui()
@@ -2947,6 +2963,7 @@ class ShowBase(DirectObject.DirectObject):
                 return task.again
                 return task.again
 
 
             self.taskMgr.add(tkLoop, 'tkLoop')
             self.taskMgr.add(tkLoop, 'tkLoop')
+        self.tkRootCreated = True
 
 
     def __tkTimerCallback(self):
     def __tkTimerCallback(self):
         if not Thread.getCurrentThread().getCurrentTask():
         if not Thread.getCurrentThread().getCurrentTask():

+ 2 - 4
direct/src/showbase/VFSImporter.py

@@ -2,6 +2,7 @@ __all__ = ['register', 'sharedPackages',
            'reloadSharedPackage', 'reloadSharedPackages']
            'reloadSharedPackage', 'reloadSharedPackages']
 
 
 from panda3d.core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
 from panda3d.core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
+from direct.stdpy.file import open
 import sys
 import sys
 import marshal
 import marshal
 import imp
 import imp
@@ -173,10 +174,7 @@ class VFSLoader:
         filename = Filename(self.filename)
         filename = Filename(self.filename)
         filename.setExtension('py')
         filename.setExtension('py')
         filename.setText()
         filename.setText()
-        vfile = vfs.getFile(filename)
-        if not vfile:
-            raise IOError("Could not find '%s'" % (filename))
-        return vfile.readFile(True)
+        return open(self.filename, self.desc[1]).read()
 
 
     def _import_extension_module(self, fullname):
     def _import_extension_module(self, fullname):
         """ Loads the binary shared object as a Python module, and
         """ Loads the binary shared object as a Python module, and

+ 1 - 1
direct/src/showutil/FreezeTool.py

@@ -1190,7 +1190,7 @@ class Freezer:
 
 
             if self.storePythonSource:
             if self.storePythonSource:
                 filename += '.py'
                 filename += '.py'
-                stream = StringStream('')
+                stream = StringStream(b'')
                 if multifile.findSubfile(filename) < 0:
                 if multifile.findSubfile(filename) < 0:
                     multifile.addSubfile(filename, stream, 0)
                     multifile.addSubfile(filename, stream, 0)
                     multifile.flush()
                     multifile.flush()

+ 3 - 3
direct/src/tkpanels/ParticlePanel.py

@@ -1976,9 +1976,9 @@ class ParticlePanel(AppShell):
         self.particles.renderer.setAlphaDisable(
         self.particles.renderer.setAlphaDisable(
             self.getVariable('Sprite Renderer', 'Alpha Disable').get())
             self.getVariable('Sprite Renderer', 'Alpha Disable').get())
     def setRendererColorBlendAttrib(self, rendererName, blendMethodStr, incomingOperandStr, fbufferOperandStr):
     def setRendererColorBlendAttrib(self, rendererName, blendMethodStr, incomingOperandStr, fbufferOperandStr):
-        self.particles.getRenderer().setColorBlendMode(eval('ColorBlendAttrib.'+blendMethodStr),
-                                                       eval('ColorBlendAttrib.'+incomingOperandStr),
-                                                       eval('ColorBlendAttrib.'+fbufferOperandStr))
+        self.particles.getRenderer().setColorBlendMode(getattr(ColorBlendAttrib, blendMethodStr),
+                                                       getattr(ColorBlendAttrib, incomingOperandStr),
+                                                       getattr(ColorBlendAttrib, fbufferOperandStr))
 
 
         if(blendMethodStr in ['MAdd','MSubtract','MInvSubtract']):
         if(blendMethodStr in ['MAdd','MSubtract','MInvSubtract']):
             self.getWidget(rendererName,'Incoming Op.').pack(fill = X)
             self.getWidget(rendererName,'Incoming Op.').pack(fill = X)

+ 20 - 0
doc/ReleaseNotes

@@ -1,3 +1,23 @@
+------------------------  RELEASE 1.9.3  ------------------------
+
+This issue fixes several bugs that were still found in 1.9.2.
+
+* 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 loading models from 'models' package with models/ prefix
+* Fix random crashes in task system
+* Fix memory leaks in BulletTriangleMesh
+* Fix loading old models with MovingPart<LMatrix4f>
+* Improve performance of CPU vertex animation somewhat
+* Show framebuffer properties when fbprop request fails
+* Show error instead of crash on use of object before __init__
+* Fix hang on exit when using Python task on threaded task chain
+* Fix inability to get RGBA renderbuffer in certain cases
+* Work around GLSL issue with #pragma and certain Intel drivers
+* Improve performance of texture load and store operations
+* Fix crashes with pbuffers on Intel cards on Windows
+* Support for Autodesk Maya 2016.5
+
 ------------------------  RELEASE 1.9.2  ------------------------
 ------------------------  RELEASE 1.9.2  ------------------------
 
 
 This is a minor bugfix release, fixing a few minor issues that
 This is a minor bugfix release, fixing a few minor issues that

+ 148 - 148
dtool/src/cppparser/cppBison.cxx.prebuilt

@@ -885,11 +885,11 @@ static const yytype_uint16 yyrline[] =
 {
 {
        0,   424,   424,   425,   429,   436,   437,   438,   442,   443,
        0,   424,   424,   425,   429,   436,   437,   438,   442,   443,
      447,   451,   464,   463,   475,   476,   477,   478,   479,   480,
      447,   451,   464,   463,   475,   476,   477,   478,   479,   480,
-     481,   482,   495,   504,   508,   516,   520,   524,   535,   556,
-     586,   603,   631,   668,   690,   723,   745,   756,   770,   769,
-     784,   788,   792,   803,   807,   811,   815,   819,   823,   827,
-     831,   835,   839,   843,   847,   855,   856,   860,   861,   865,
-     869,   878,   886,   898,   897,   913,   912,   934,   942,   953,
+     481,   494,   503,   507,   515,   519,   523,   534,   555,   585,
+     602,   630,   667,   689,   722,   744,   755,   769,   768,   783,
+     787,   791,   802,   806,   810,   814,   818,   822,   826,   830,
+     834,   838,   842,   846,   854,   855,   859,   860,   864,   868,
+     877,   885,   893,   898,   897,   913,   912,   934,   942,   953,
      962,   976,   975,   991,   990,  1005,  1020,  1026,  1035,  1042,
      962,   976,   975,   991,   990,  1005,  1020,  1026,  1035,  1042,
     1055,  1054,  1079,  1078,  1106,  1105,  1136,  1135,  1154,  1153,
     1055,  1054,  1079,  1078,  1106,  1105,  1136,  1135,  1154,  1153,
     1174,  1173,  1205,  1204,  1230,  1243,  1247,  1251,  1255,  1259,
     1174,  1173,  1205,  1204,  1230,  1243,  1247,  1251,  1255,  1259,
@@ -1071,8 +1071,8 @@ static const yytype_int16 yypact[] =
     -703,   -20,  -703,  -703,  1983,  2722,  2722,  -703,  1244,  -703,
     -703,   -20,  -703,  -703,  1983,  2722,  2722,  -703,  1244,  -703,
     2722,  -703,  -703,    62,  -703,  -703,  -703,  -703,    66,    48,
     2722,  -703,  -703,    62,  -703,  -703,  -703,  -703,    66,    48,
      959,  -703,  -703,  -703,  -703,  -703,  -703,  5378,  5378,  -703,
      959,  -703,  -703,  -703,  -703,  -703,  -703,  5378,  5378,  -703,
-    5378,   892,  5378,   160,  -703,  5286,   225,   227,   233,   251,
-    5378,  2255,   191,   269,   272,  5378,  5378,   263,  5300,  5378,
+    5378,   892,  5378,   160,  -703,  5335,   225,   227,   233,   251,
+    5378,  2255,   191,   269,   272,  5378,  5378,   263,  5263,  5378,
     5378,  2691,  5378,  5378,  -703,    63,  -703,  -703,  -703,  3269,
     5378,  2691,  5378,  5378,  -703,    63,  -703,  -703,  -703,  3269,
     -703,  -703,  -703,  -703,  -703,  -703,  2822,  4474,  2822,  2822,
     -703,  -703,  -703,  -703,  -703,  -703,  2822,  4474,  2822,  2822,
     2822,  2822,  4474,  2822,  4474,  2822,  2822,  2822,  -703,  -703,
     2822,  2822,  4474,  2822,  4474,  2822,  2822,  2822,  -703,  -703,
@@ -1126,7 +1126,7 @@ static const yytype_int16 yypact[] =
      552,   623,   -21,   555,   556,   932,  -703,  -703,   623,   557,
      552,   623,   -21,   555,   556,   932,  -703,  -703,   623,   557,
      557,   557,   557,   557,   265,  2822,  2822,  -703,  -703,   558,
      557,   557,   557,   557,   265,  2822,  2822,  -703,  -703,   558,
     -703,  2822,  -703,  4125,   568,   574,  -703,  -703,  -703,   -23,
     -703,  2822,  -703,  4125,   568,   574,  -703,  -703,  -703,   -23,
-     577,   579,   584,  5063,    41,  -703,   582,   623,   587,  5322,
+     577,   579,   584,  5063,    41,  -703,   582,   623,   587,  5309,
     4236,    44,   529,  -703,   308,  -703,  5378,  -703,  -703,  -703,
     4236,    44,   529,  -703,   308,  -703,  5378,  -703,  -703,  -703,
     -703,  -703,  -703,  -703,   601,   586,   611,  -703,  -703,  4682,
     -703,  -703,  -703,  -703,   601,   586,   611,  -703,  -703,  4682,
     -703,  -703,   612,   605,   615,  -703,   609,  2822,  2822,  2822,
     -703,  -703,   612,   605,   615,  -703,   609,  2822,  2822,  2822,
@@ -1211,11 +1211,11 @@ static const yytype_uint16 yydefact[] =
      593,   261,   269,   343,   344,   346,   347,   328,     0,     0,
      593,   261,   269,   343,   344,   346,   347,   328,     0,     0,
      358,   325,   357,   352,   349,   348,   351,   329,     0,   330,
      358,   325,   357,   352,   349,   348,   351,   329,     0,   330,
      350,   360,   345,   680,     4,   263,   264,   265,     0,   314,
      350,   360,   345,   680,     4,   263,   264,   265,     0,   314,
-       0,   260,   340,   341,   342,     1,    21,   680,   680,    22,
-     680,   680,   680,     0,    38,   680,     0,     0,     0,     0,
+       0,   260,   340,   341,   342,     1,    20,   680,   680,    21,
+     680,   680,   680,     0,    37,   680,     0,     0,     0,     0,
      680,     0,     0,     0,     0,   680,   680,     0,   680,   680,
      680,     0,     0,     0,     0,   680,   680,     0,   680,   680,
-     680,     0,   680,   680,     6,     0,    16,     7,    19,     0,
-      14,    59,    15,    17,    18,    40,   680,     0,   680,   680,
+     680,     0,   680,   680,     6,     0,    16,     7,    18,     0,
+      14,    58,    15,    17,    62,    39,   680,     0,   680,   680,
      680,   680,     0,   680,     0,   680,   680,   680,   282,   287,
      680,   680,     0,   680,     0,   680,   680,   680,   282,   287,
        0,     0,   553,     0,     0,   281,     0,   680,   680,     0,
        0,     0,   553,     0,     0,   281,     0,   680,   680,     0,
        0,     0,   680,   680,   562,   560,   559,   561,   558,   261,
        0,     0,   680,   680,   562,   560,   559,   561,   558,   261,
@@ -1228,10 +1228,10 @@ static const yytype_uint16 yydefact[] =
      359,   349,   354,   353,   356,   262,   355,     0,   680,   680,
      359,   349,   354,   353,   356,   262,   355,     0,   680,   680,
      680,   680,   680,   680,     0,   290,   248,   680,   673,   674,
      680,   680,   680,   680,     0,   290,   248,   680,   673,   674,
      675,     0,   316,   664,   665,   667,   292,   266,   294,   680,
      675,     0,   316,   664,   665,   667,   292,   266,   294,   680,
-      51,    50,    52,   680,    41,    46,    23,   680,     0,    44,
-       0,     0,     0,     0,    49,   680,     0,    26,    25,    24,
-      47,    43,     0,     0,   146,     0,    53,     0,    20,     0,
-       0,    45,    48,     0,   289,   271,   280,     0,     0,     0,
+      50,    49,    51,   680,    40,    45,    22,   680,     0,    43,
+       0,     0,     0,     0,    48,   680,     0,    25,    24,    23,
+      46,    42,     0,     0,   146,     0,    52,     0,    19,     0,
+       0,    44,    47,     0,   289,   271,   280,     0,     0,     0,
        0,    12,     0,     0,     0,   288,    63,   273,   274,   275,
        0,    12,     0,     0,     0,   288,    63,   273,   274,   275,
      314,     0,   270,     0,   492,   491,     0,     0,     0,     0,
      314,     0,   270,     0,   492,   491,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,   283,   680,
        0,     0,     0,     0,     0,     0,     0,     0,   283,   680,
@@ -1242,12 +1242,12 @@ static const yytype_uint16 yydefact[] =
        0,   291,     0,   680,     0,   680,   680,   680,   680,   680,
        0,   291,     0,   680,     0,   680,   680,   680,   680,   680,
      253,   240,     0,   249,     0,   250,   252,   251,   179,   680,
      253,   240,     0,   249,     0,   250,   252,   251,   179,   680,
        0,     0,   680,   680,     0,   180,   183,   680,   178,   680,
        0,     0,   680,   680,     0,   180,   183,   680,   178,   680,
-     322,     0,   319,   318,   313,   317,     0,   680,   680,    42,
-      39,   680,     0,     0,     0,     0,     0,   680,   331,     0,
+     322,     0,   319,   318,   313,   317,     0,   680,   680,    41,
+      38,   680,     0,     0,     0,     0,     0,   680,   331,     0,
      680,   289,   271,     0,     0,   288,    71,     0,   337,     0,
      680,   289,   271,     0,     0,   288,    71,     0,   337,     0,
-       0,    55,    57,    80,    82,   289,   271,    65,     0,     0,
-     680,   272,   680,     0,   361,   196,     0,     0,    61,   361,
-     201,     0,    62,    60,     0,   278,   316,   276,   538,   552,
+       0,    54,    56,    80,    82,   289,   271,    65,     0,     0,
+     680,   272,   680,     0,   361,   196,     0,     0,    60,   361,
+     201,     0,    61,    59,     0,   278,   316,   276,   538,   552,
      544,   540,   542,   543,     0,   550,     0,   549,   539,   546,
      544,   540,   542,   543,     0,   550,     0,   549,   539,   546,
        0,     0,     0,   545,   548,   551,     0,   555,   556,   547,
        0,     0,     0,   545,   548,   551,     0,   555,   556,   547,
      541,   533,   494,    96,   680,   680,    95,   656,     0,   583,
      541,   533,   494,    96,   680,   680,    95,   656,     0,   583,
@@ -1267,8 +1267,8 @@ static const yytype_uint16 yydefact[] =
        0,   680,   680,     0,     0,   680,   181,   184,   680,   235,
        0,   680,   680,     0,     0,   680,   181,   184,   680,   235,
      231,   232,   234,   233,     0,     0,   680,   214,   194,   255,
      231,   232,   234,   233,     0,     0,   680,   214,   194,   255,
      320,     0,   293,     0,     0,   299,   298,   336,   680,     0,
      320,     0,   293,     0,     0,   299,   298,   336,   680,     0,
-       0,     0,     0,   680,     0,    37,   151,   680,   153,   680,
-       0,   680,     0,    72,   680,   338,   680,    56,   647,   643,
+       0,     0,     0,   680,     0,    36,   151,   680,   153,   680,
+       0,   680,     0,    72,   680,   338,   680,    55,   647,   643,
      646,   649,   650,   186,     0,     0,     0,   645,   651,     0,
      646,   649,   650,   186,     0,     0,     0,   645,   651,     0,
      653,   652,     0,     0,     0,   644,     0,     0,     0,     0,
      653,   652,     0,     0,     0,   644,     0,     0,     0,     0,
        0,     0,     0,     0,   187,   218,   190,   219,   601,   648,
        0,     0,     0,     0,   187,   218,   190,   219,   601,   648,
@@ -1286,9 +1286,9 @@ static const yytype_uint16 yydefact[] =
      239,   195,     0,   324,   671,     0,   670,     0,     0,   300,
      239,   195,     0,   324,   671,     0,   670,     0,     0,   300,
        0,   302,   661,   680,     0,   680,     0,     0,     0,     0,
        0,   302,   661,   680,     0,   680,     0,     0,     0,     0,
        0,   332,     0,     0,   680,     0,   142,   145,   143,   150,
        0,   332,     0,     0,   680,     0,   142,   145,   143,   150,
-       0,   155,   192,    74,   680,     0,    76,    54,     0,     0,
+       0,   155,   192,    74,   680,     0,    76,    53,     0,     0,
        0,   609,     0,     0,     0,     0,   617,   616,   615,   614,
        0,   609,     0,     0,     0,     0,   617,   616,   615,   614,
-       0,     0,   613,    58,   189,     0,     0,     0,     0,     0,
+       0,     0,   613,    57,   189,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,   680,
        0,     0,     0,     0,     0,     0,     0,     0,     0,   680,
        0,     0,   680,     0,    69,    92,   227,   680,     0,     0,
        0,     0,   680,     0,    69,    92,   227,   680,     0,     0,
@@ -1309,7 +1309,7 @@ static const yytype_uint16 yydefact[] =
      195,     0,   536,   535,   537,   534,   680,   680,   176,   101,
      195,     0,   536,   535,   537,   534,   680,   680,   176,   101,
        0,     0,     0,   216,     0,     0,   680,   237,   321,     0,
        0,     0,     0,   216,     0,     0,   680,   237,   321,     0,
      305,     0,   304,     0,   303,   663,     0,     0,     0,   662,
      305,     0,   304,     0,   303,   663,     0,     0,     0,   662,
-     680,   301,   334,     0,    27,     0,     0,     0,    36,   152,
+     680,   301,   334,     0,    26,     0,     0,     0,    35,   152,
      156,   154,     0,     0,     0,     0,     0,     0,     0,     0,
      156,   154,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,   193,   495,     0,    78,     0,
        0,     0,     0,     0,     0,   193,   495,     0,    78,     0,
        0,     0,     0,   680,     0,     0,     0,     0,     0,     0,
        0,     0,     0,   680,     0,     0,     0,     0,     0,     0,
@@ -1326,17 +1326,17 @@ static const yytype_uint16 yydefact[] =
        0,     0,     0,     0,    77,   608,     0,     0,     0,     0,
        0,     0,     0,     0,    77,   608,     0,     0,     0,     0,
      607,     0,   611,   612,   602,     0,   638,   637,    88,   680,
      607,     0,   611,   612,   602,     0,   638,   637,    88,   680,
       70,     0,   680,    85,   488,     0,   680,   361,   680,   680,
       70,     0,   680,    85,   488,     0,   680,   361,   680,   680,
-     680,   680,     0,    28,     0,    33,    35,     0,    30,     0,
+     680,   680,     0,    27,     0,    32,    34,     0,    29,     0,
        0,     0,     0,     0,     0,     0,   531,   517,   518,   519,
        0,     0,     0,     0,     0,     0,   531,   517,   518,   519,
      520,   521,   522,   523,   524,   530,     0,   514,   515,   516,
      520,   521,   522,   523,   524,   530,     0,   514,   515,   516,
      512,   513,   509,   510,   511,   529,   528,     0,     0,    79,
      512,   513,   509,   510,   511,   529,   528,     0,     0,    79,
        0,     0,   610,     0,     0,   636,   680,     0,   680,    91,
        0,     0,   610,     0,     0,   636,   680,     0,   680,    91,
      213,   172,     0,   259,   258,   257,   238,     0,     0,     0,
      213,   172,     0,   259,   258,   257,   238,     0,     0,     0,
        0,   502,     0,     0,     0,   501,     0,   496,     0,   527,
        0,   502,     0,     0,     0,   501,     0,   496,     0,   527,
-     526,     0,     0,     0,     0,     0,   680,    93,   600,    29,
-       0,     0,    31,     0,     0,     0,     0,   525,   605,   604,
+     526,     0,     0,     0,     0,     0,   680,    93,   600,    28,
+       0,     0,    30,     0,     0,     0,     0,   525,   605,   604,
      606,   603,   680,   680,     0,     0,     0,     0,     0,     0,
      606,   603,   680,   680,     0,     0,     0,     0,     0,     0,
-     680,    87,    34,    32,   499,   498,   500,   497,    89
+     680,    87,    33,    31,   499,   498,   500,   497,    89
 };
 };
 
 
   /* YYPGOTO[NTERM-NUM].  */
   /* YYPGOTO[NTERM-NUM].  */
@@ -1907,24 +1907,24 @@ static const yytype_int16 yytable[] =
       86,    87,   108,   109,     0,     0,     0,   110,     0,    88,
       86,    87,   108,   109,     0,     0,     0,   110,     0,    88,
        0,     0,   111,   112,     0,   113,     0,    89,     0,    90,
        0,     0,   111,   112,     0,   113,     0,    89,     0,    90,
       91,    92,    93,   114,     0,     0,    94,     0,     0,     0,
       91,    92,    93,   114,     0,     0,    94,     0,     0,     0,
-      95,     0,     0,     0,    96,    97,    98,    99,   100,   101,
-     115,     0,  1160,     0,     0,   102,   103,   104,   105,     0,
-       0,     0,     0,     0,   106,   107,    87,     0,   108,   109,
-       0,     0,     0,   110,    88,     0,     0,     0,   111,   112,
-      87,   113,     0,     0,    90,    91,    92,     0,    88,     0,
-       0,     0,     0,     0,     0,   249,     0,     0,    90,    91,
-      92,     0,    87,   100,   258,     0,   115,     0,     0,   249,
-      88,     0,     0,   105,     0,     0,     0,   100,     0,   106,
-      90,    91,    92,     0,   109,     0,     0,   105,     0,     0,
-       0,   249,     0,   106,   112,     0,   113,     0,   109,   100,
-       0,     0,     0,     0,     0,     0,     0,     0,   112,   105,
-     113,     0,     0,     0,     0,   106,     0,     0,    87,   108,
-     109,   115,     0,     0,     0,  -144,    88,     0,     0,     0,
-     112,     0,   113,     0,     0,   115,    90,    91,    92,     0,
-       0,     0,     0,     0,     0,     0,     0,   249,     0,     0,
-       0,     0,     0,     0,     0,   100,     0,   115,     0,     0,
+      95,     0,     0,    87,    96,    97,    98,    99,   100,   101,
+     115,    88,  1160,     0,     0,   102,   103,   104,   105,     0,
+       0,    90,    91,    92,   106,   107,     0,     0,   108,   109,
+       0,     0,   249,   110,     0,     0,     0,     0,   111,   112,
+     100,   113,     0,     0,     0,     0,     0,     0,     0,    87,
+     105,     0,     0,     0,     0,     0,   106,    88,     0,     0,
+       0,   109,     0,     0,     0,     0,   115,    90,    91,    92,
+     111,   112,     0,   113,     0,    87,     0,     0,   249,     0,
+       0,     0,     0,    88,     0,     0,   100,     0,  -144,     0,
+       0,     0,     0,    90,    91,    92,   105,     0,   115,     0,
+       0,     0,   106,     0,   249,     0,   108,   109,     0,     0,
+       0,     0,   100,   258,     0,     0,   111,   112,    87,   113,
+       0,     0,   105,     0,     0,     0,    88,     0,   106,     0,
+       0,     0,     0,   109,     0,     0,    90,    91,    92,     0,
+       0,     0,     0,   112,   115,   113,     0,   249,     0,     0,
+       0,     0,     0,     0,     0,   100,     0,     0,     0,     0,
        0,     0,     0,     0,     0,   105,     0,     0,     0,     0,
        0,     0,     0,     0,     0,   105,     0,     0,     0,     0,
-       0,   106,     0,     0,     0,     0,   109,     0,     0,     0,
+     115,   106,     0,     0,     0,     0,   109,     0,     0,     0,
        0,     0,     0,     0,     0,     0,   112,     0,   113,     0,
        0,     0,     0,     0,     0,     0,   112,     0,   113,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
@@ -2464,24 +2464,24 @@ static const yytype_int16 yycheck[] =
       49,    50,   107,   108,    -1,    -1,    -1,   112,    -1,    58,
       49,    50,   107,   108,    -1,    -1,    -1,   112,    -1,    58,
       -1,    -1,   117,   118,    -1,   120,    -1,    66,    -1,    68,
       -1,    -1,   117,   118,    -1,   120,    -1,    66,    -1,    68,
       69,    70,    71,   128,    -1,    -1,    75,    -1,    -1,    -1,
       69,    70,    71,   128,    -1,    -1,    75,    -1,    -1,    -1,
-      79,    -1,    -1,    -1,    83,    84,    85,    86,    87,    88,
-     145,    -1,   147,    -1,    -1,    94,    95,    96,    97,    -1,
-      -1,    -1,    -1,    -1,   103,   104,    50,    -1,   107,   108,
-      -1,    -1,    -1,   112,    58,    -1,    -1,    -1,   117,   118,
-      50,   120,    -1,    -1,    68,    69,    70,    -1,    58,    -1,
-      -1,    -1,    -1,    -1,    -1,    79,    -1,    -1,    68,    69,
-      70,    -1,    50,    87,    88,    -1,   145,    -1,    -1,    79,
-      58,    -1,    -1,    97,    -1,    -1,    -1,    87,    -1,   103,
-      68,    69,    70,    -1,   108,    -1,    -1,    97,    -1,    -1,
-      -1,    79,    -1,   103,   118,    -1,   120,    -1,   108,    87,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   118,    97,
-     120,    -1,    -1,    -1,    -1,   103,    -1,    -1,    50,   107,
-     108,   145,    -1,    -1,    -1,   135,    58,    -1,    -1,    -1,
-     118,    -1,   120,    -1,    -1,   145,    68,    69,    70,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    79,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    87,    -1,   145,    -1,    -1,
+      79,    -1,    -1,    50,    83,    84,    85,    86,    87,    88,
+     145,    58,   147,    -1,    -1,    94,    95,    96,    97,    -1,
+      -1,    68,    69,    70,   103,   104,    -1,    -1,   107,   108,
+      -1,    -1,    79,   112,    -1,    -1,    -1,    -1,   117,   118,
+      87,   120,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    50,
+      97,    -1,    -1,    -1,    -1,    -1,   103,    58,    -1,    -1,
+      -1,   108,    -1,    -1,    -1,    -1,   145,    68,    69,    70,
+     117,   118,    -1,   120,    -1,    50,    -1,    -1,    79,    -1,
+      -1,    -1,    -1,    58,    -1,    -1,    87,    -1,   135,    -1,
+      -1,    -1,    -1,    68,    69,    70,    97,    -1,   145,    -1,
+      -1,    -1,   103,    -1,    79,    -1,   107,   108,    -1,    -1,
+      -1,    -1,    87,    88,    -1,    -1,   117,   118,    50,   120,
+      -1,    -1,    97,    -1,    -1,    -1,    58,    -1,   103,    -1,
+      -1,    -1,    -1,   108,    -1,    -1,    68,    69,    70,    -1,
+      -1,    -1,    -1,   118,   145,   120,    -1,    79,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    87,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    97,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    97,    -1,    -1,    -1,    -1,
-      -1,   103,    -1,    -1,    -1,    -1,   108,    -1,    -1,    -1,
+     145,   103,    -1,    -1,    -1,    -1,   108,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,   118,    -1,   120,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,   118,    -1,   120,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
@@ -2634,9 +2634,9 @@ static const yytype_uint16 yyr1[] =
        0,   150,   151,   151,   151,   152,   152,   152,   153,   153,
        0,   150,   151,   151,   151,   152,   152,   152,   153,   153,
      154,   154,   156,   155,   157,   157,   157,   157,   157,   157,
      154,   154,   156,   155,   157,   157,   157,   157,   157,   157,
      157,   157,   157,   157,   157,   157,   157,   157,   157,   157,
      157,   157,   157,   157,   157,   157,   157,   157,   157,   157,
-     157,   157,   157,   157,   157,   157,   157,   157,   159,   158,
+     157,   157,   157,   157,   157,   157,   157,   159,   158,   160,
      160,   160,   160,   160,   160,   160,   160,   160,   160,   160,
      160,   160,   160,   160,   160,   160,   160,   160,   160,   160,
-     160,   160,   160,   160,   160,   161,   161,   162,   162,   163,
+     160,   160,   160,   160,   161,   161,   162,   162,   163,   163,
      163,   163,   163,   165,   164,   166,   164,   167,   167,   168,
      163,   163,   163,   165,   164,   166,   164,   167,   167,   168,
      168,   170,   169,   171,   169,   169,   172,   172,   173,   173,
      168,   170,   169,   171,   169,   169,   172,   172,   173,   173,
      175,   174,   176,   174,   178,   177,   179,   177,   180,   177,
      175,   174,   176,   174,   178,   177,   179,   177,   180,   177,
@@ -2706,12 +2706,12 @@ static const yytype_uint16 yyr1[] =
 static const yytype_uint8 yyr2[] =
 static const yytype_uint8 yyr2[] =
 {
 {
        0,     2,     2,     2,     2,     1,     2,     2,     1,     3,
        0,     2,     2,     2,     2,     1,     2,     2,     1,     3,
-       4,     4,     0,     5,     1,     1,     1,     1,     1,     1,
-       2,     1,     1,     2,     2,     2,     2,     7,     9,    11,
-       9,    11,    13,     9,    13,     9,     7,     5,     0,     3,
-       1,     2,     3,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     6,     1,     3,     1,     4,     1,
-       3,     3,     3,     0,     4,     0,     5,     2,     4,     2,
+       4,     4,     0,     5,     1,     1,     1,     1,     1,     2,
+       1,     1,     2,     2,     2,     2,     7,     9,    11,     9,
+      11,    13,     9,    13,     9,     7,     5,     0,     3,     1,
+       2,     3,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     6,     1,     3,     1,     4,     1,     3,
+       3,     3,     1,     0,     4,     0,     5,     2,     4,     2,
        4,     0,     4,     0,     5,     3,     2,     4,     2,     4,
        4,     0,     4,     0,     5,     3,     2,     4,     2,     4,
        0,     6,     0,     6,     0,     7,     0,    11,     0,    12,
        0,     6,     0,     6,     0,     7,     0,    11,     0,    12,
        0,     8,     0,     9,     1,     1,     1,     2,     2,     2,
        0,     8,     0,     9,     1,     1,     1,     2,     2,     2,
@@ -3597,8 +3597,8 @@ yyreduce:
 #line 3598 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3598 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 21:
-#line 483 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 20:
+#line 482 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   if (publish_nest_level != 0) {
   if (publish_nest_level != 0) {
     yyerror("Unclosed __begin_publish", publish_loc);
     yyerror("Unclosed __begin_publish", publish_loc);
@@ -3614,8 +3614,8 @@ yyreduce:
 #line 3615 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3615 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 22:
-#line 496 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 21:
+#line 495 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   if (publish_nest_level != 1) {
   if (publish_nest_level != 1) {
     yyerror("Unmatched __end_publish", (yylsp[0]));
     yyerror("Unmatched __end_publish", (yylsp[0]));
@@ -3627,16 +3627,16 @@ yyreduce:
 #line 3628 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3628 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 23:
-#line 505 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 22:
+#line 504 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   current_scope->set_current_vis(V_published);
   current_scope->set_current_vis(V_published);
 }
 }
 #line 3636 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3636 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 24:
-#line 509 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 23:
+#line 508 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   if (publish_nest_level > 0) {
   if (publish_nest_level > 0) {
     current_scope->set_current_vis(V_published);
     current_scope->set_current_vis(V_published);
@@ -3647,24 +3647,24 @@ yyreduce:
 #line 3648 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3648 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 25:
-#line 517 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 24:
+#line 516 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   current_scope->set_current_vis(V_protected);
   current_scope->set_current_vis(V_protected);
 }
 }
 #line 3656 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3656 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 26:
-#line 521 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 25:
+#line 520 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   current_scope->set_current_vis(V_private);
   current_scope->set_current_vis(V_private);
 }
 }
 #line 3664 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3664 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 27:
-#line 525 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 26:
+#line 524 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
 
 
   CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
@@ -3678,8 +3678,8 @@ yyreduce:
 #line 3679 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3679 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 28:
-#line 536 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 27:
+#line 535 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3703,8 +3703,8 @@ yyreduce:
 #line 3704 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3704 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 29:
-#line 557 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 28:
+#line 556 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3737,8 +3737,8 @@ yyreduce:
 #line 3738 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3738 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 30:
-#line 587 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 29:
+#line 586 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3758,8 +3758,8 @@ yyreduce:
 #line 3759 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3759 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 31:
-#line 604 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 30:
+#line 603 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *length_getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *length_getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3790,8 +3790,8 @@ yyreduce:
 #line 3791 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3791 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 32:
-#line 632 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 31:
+#line 631 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *length_getter = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *length_getter = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3831,8 +3831,8 @@ yyreduce:
 #line 3832 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3832 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 33:
-#line 669 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 32:
+#line 668 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *hasser = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *hasser = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
   if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3857,8 +3857,8 @@ yyreduce:
 #line 3858 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3858 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 34:
-#line 691 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 33:
+#line 690 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *hasser = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *hasser = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
   if (hasser == (CPPDeclaration *)NULL || hasser->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3894,8 +3894,8 @@ yyreduce:
 #line 3895 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3895 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 35:
-#line 724 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 34:
+#line 723 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer);
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
   if (length_getter == (CPPDeclaration *)NULL || length_getter->get_subtype() != CPPDeclaration::ST_function_group) {
@@ -3920,8 +3920,8 @@ yyreduce:
 #line 3921 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3921 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 36:
-#line 746 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 35:
+#line 745 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPExpression::Result result = (yyvsp[-4].u.expr)->evaluate();
   CPPExpression::Result result = (yyvsp[-4].u.expr)->evaluate();
   if (result._type == CPPExpression::RT_error) {
   if (result._type == CPPExpression::RT_error) {
@@ -3935,8 +3935,8 @@ yyreduce:
 #line 3936 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3936 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 37:
-#line 757 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 36:
+#line 756 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   // This alternative version of static_assert was introduced in C++17.
   // This alternative version of static_assert was introduced in C++17.
   CPPExpression::Result result = (yyvsp[-2].u.expr)->evaluate();
   CPPExpression::Result result = (yyvsp[-2].u.expr)->evaluate();
@@ -3949,8 +3949,8 @@ yyreduce:
 #line 3950 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3950 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 38:
-#line 770 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 37:
+#line 769 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"),
   CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"),
                                      V_public);
                                      V_public);
@@ -3959,8 +3959,8 @@ yyreduce:
 #line 3960 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3960 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 39:
-#line 776 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 38:
+#line 775 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   delete current_scope;
   delete current_scope;
   pop_scope();
   pop_scope();
@@ -3968,24 +3968,24 @@ yyreduce:
 #line 3969 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3969 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 40:
-#line 785 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 39:
+#line 784 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = 0;
   (yyval.u.integer) = 0;
 }
 }
 #line 3977 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3977 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 41:
-#line 789 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 40:
+#line 788 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern;
 }
 }
 #line 3985 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 3985 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 42:
-#line 793 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 41:
+#line 792 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern;
   if ((yyvsp[-1].str) == "C") {
   if ((yyvsp[-1].str) == "C") {
@@ -3999,96 +3999,96 @@ yyreduce:
 #line 4000 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4000 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 43:
-#line 804 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 42:
+#line 803 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_static;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_static;
 }
 }
 #line 4008 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4008 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 44:
-#line 808 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 43:
+#line 807 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_inline;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_inline;
 }
 }
 #line 4016 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4016 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 45:
-#line 812 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 44:
+#line 811 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_virtual;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_virtual;
 }
 }
 #line 4024 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4024 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 46:
-#line 816 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 45:
+#line 815 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_explicit;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_explicit;
 }
 }
 #line 4032 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4032 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 47:
-#line 820 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 46:
+#line 819 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_register;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_register;
 }
 }
 #line 4040 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4040 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 48:
-#line 824 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 47:
+#line 823 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_volatile;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_volatile;
 }
 }
 #line 4048 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4048 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 49:
-#line 828 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 48:
+#line 827 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_mutable;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_mutable;
 }
 }
 #line 4056 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4056 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 50:
-#line 832 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 49:
+#line 831 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_constexpr;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_constexpr;
 }
 }
 #line 4064 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4064 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 51:
-#line 836 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 50:
+#line 835 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_blocking;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_blocking;
 }
 }
 #line 4072 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4072 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 52:
-#line 840 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 51:
+#line 839 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extension;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extension;
 }
 }
 #line 4080 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4080 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 53:
-#line 844 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 52:
+#line 843 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_thread_local;
   (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_thread_local;
 }
 }
 #line 4088 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4088 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 54:
-#line 848 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 53:
+#line 847 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   // Ignore attribute specifiers for now.
   // Ignore attribute specifiers for now.
   (yyval.u.integer) = (yyvsp[0].u.integer);
   (yyval.u.integer) = (yyvsp[0].u.integer);
@@ -4096,16 +4096,16 @@ yyreduce:
 #line 4097 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4097 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 59:
-#line 866 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 58:
+#line 865 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   /* multiple_var_declaration adds itself to the scope. */
   /* multiple_var_declaration adds itself to the scope. */
 }
 }
 #line 4105 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4105 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 60:
-#line 870 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 59:
+#line 869 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   // We don't really care about the storage class here.  In fact, it's
   // We don't really care about the storage class here.  In fact, it's
   // not actually legal to define a class or struct using a particular
   // not actually legal to define a class or struct using a particular
@@ -4117,8 +4117,8 @@ yyreduce:
 #line 4118 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4118 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 61:
-#line 879 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 60:
+#line 878 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   if ((yyvsp[-1].u.instance) != (CPPInstance *)NULL) {
   if ((yyvsp[-1].u.instance) != (CPPInstance *)NULL) {
     (yyvsp[-1].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer));
     (yyvsp[-1].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer));
@@ -4129,8 +4129,8 @@ yyreduce:
 #line 4130 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
 #line 4130 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     break;
     break;
 
 
-  case 62:
-#line 887 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
+  case 61:
+#line 886 "dtool/src/cppparser/cppBison.yxx" /* yacc.c:1646  */
     {
     {
   if ((yyvsp[-1].u.instance) != (CPPInstance *)NULL) {
   if ((yyvsp[-1].u.instance) != (CPPInstance *)NULL) {
     (yyvsp[-1].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer));
     (yyvsp[-1].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer));

+ 1 - 1
dtool/src/cppparser/cppBison.yxx

@@ -476,7 +476,6 @@ declaration:
         | template_declaration
         | template_declaration
         | extern_c
         | extern_c
         | namespace_declaration
         | namespace_declaration
-        | using_declaration
         | friend_declaration
         | friend_declaration
         | KW_TYPEDEF typedef_declaration
         | KW_TYPEDEF typedef_declaration
         | KW_BEGIN_PUBLISH
         | KW_BEGIN_PUBLISH
@@ -891,6 +890,7 @@ type_like_declaration:
     $2->set_initializer($3);
     $2->set_initializer($3);
   }
   }
 }
 }
+        | using_declaration
         ;
         ;
 
 
 multiple_var_declaration:
 multiple_var_declaration:

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

@@ -16,6 +16,7 @@
 
 
 #include "dtoolbase.h"
 #include "dtoolbase.h"
 
 
+#include "cppBisonDefs.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
 
 
 #include <vector>
 #include <vector>

+ 62 - 28
dtool/src/cppparser/cppScope.cxx

@@ -18,6 +18,7 @@
 #include "cppTypedefType.h"
 #include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppTypeDeclaration.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
+#include "cppEnumType.h"
 #include "cppInstance.h"
 #include "cppInstance.h"
 #include "cppInstanceIdentifier.h"
 #include "cppInstanceIdentifier.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
@@ -133,6 +134,66 @@ add_enum_value(CPPInstance *inst) {
   }
   }
 }
 }
 
 
+/**
+ *
+ */
+void CPPScope::
+define_typedef_type(CPPTypedefType *type, CPPPreprocessor *error_sink) {
+  string name = type->get_simple_name();
+
+  pair<Types::iterator, bool> result =
+    _types.insert(Types::value_type(name, type));
+
+  if (!result.second) {
+    CPPType *other_type = result.first->second;
+    CPPTypedefType *other_td = other_type->as_typedef_type();
+
+    // We don't do redefinitions of typedefs.  But we don't complain as long
+    // as this is actually a typedef to the previous definition.
+    if (other_type != type->_type &&
+        (other_td == NULL || !other_td->_type->is_equivalent(*type->_type))) {
+
+      if (error_sink != NULL) {
+        ostringstream errstr;
+        type->output(errstr, 0, NULL, false);
+        errstr << " has conflicting declaration as ";
+        other_type->output(errstr, 0, NULL, true);
+        error_sink->error(errstr.str(), type->_ident->_loc);
+        error_sink->error("previous definition is here",
+                          other_td->_ident->_loc);
+      }
+    }
+  } else {
+    _types[name] = type;
+  }
+
+  // This might be a templated "using" definition.
+  if (type->is_template()) {
+    CPPTemplateScope *scope = type->get_template_scope();
+    if (scope->_parameters._parameters.size() == 0) {
+      return;
+    }
+
+    string simple_name = type->get_simple_name();
+
+    pair<Templates::iterator, bool> result =
+      _templates.insert(Templates::value_type(simple_name, type));
+
+    if (!result.second) {
+      // The template was not inserted because we already had a template
+      // definition with the given name.  If the previous definition was
+      // incomplete, replace it.
+      CPPDeclaration *old_templ = (*result.first).second;
+      CPPType *old_templ_type = old_templ->as_type();
+      if (old_templ_type == NULL || old_templ_type->is_incomplete()) {
+        // The previous template definition was incomplete, maybe a forward
+        // reference; replace it with the good one.
+        (*result.first).second = type;
+      }
+    }
+  }
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -1035,39 +1096,12 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope,
                    CPPPreprocessor *error_sink) {
                    CPPPreprocessor *error_sink) {
   CPPTypedefType *def = decl->as_typedef_type();
   CPPTypedefType *def = decl->as_typedef_type();
   if (def != NULL) {
   if (def != NULL) {
-    string name = def->get_simple_name();
-
-    pair<Types::iterator, bool> result =
-      _types.insert(Types::value_type(name, def));
-
-    if (!result.second) {
-      CPPType *other_type = result.first->second;
-      CPPTypedefType *other_td = other_type->as_typedef_type();
-
-      // We don't do redefinitions of typedefs.  But we don't complain as long
-      // as this is actually a typedef to the previous definition.
-      if (other_type != def->_type &&
-          (other_td == NULL || !other_td->_type->is_equivalent(*def->_type))) {
-
-        if (error_sink != NULL) {
-          ostringstream errstr;
-          def->output(errstr, 0, NULL, false);
-          errstr << " has conflicting declaration as ";
-          other_type->output(errstr, 0, NULL, true);
-          error_sink->error(errstr.str(), def->_ident->_loc);
-          error_sink->error("previous definition is here",
-                            other_td->_ident->_loc);
-        }
-      }
-    } else {
-      _types[name] = def;
-    }
+    define_typedef_type(def, error_sink);
 
 
     CPPExtensionType *et = def->_type->as_extension_type();
     CPPExtensionType *et = def->_type->as_extension_type();
     if (et != NULL) {
     if (et != NULL) {
       define_extension_type(et, error_sink);
       define_extension_type(et, error_sink);
     }
     }
-
     return;
     return;
   }
   }
 
 

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

@@ -62,6 +62,8 @@ public:
                                CPPPreprocessor *preprocessor,
                                CPPPreprocessor *preprocessor,
                                const cppyyltype &pos);
                                const cppyyltype &pos);
   virtual void add_enum_value(CPPInstance *inst);
   virtual void add_enum_value(CPPInstance *inst);
+  virtual void define_typedef_type(CPPTypedefType *type,
+                                   CPPPreprocessor *error_sink = NULL);
   virtual void define_extension_type(CPPExtensionType *type,
   virtual void define_extension_type(CPPExtensionType *type,
                                      CPPPreprocessor *error_sink = NULL);
                                      CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void define_namespace(CPPNamespace *scope);

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

@@ -674,7 +674,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
 
 
         // If the struct name didn't have an explicit template reference
         // If the struct name didn't have an explicit template reference
         // before, now it does.
         // before, now it does.
-        if (!_ident->_names.empty() && !_ident->_names.back().has_templ()) {
+        if (_ident != NULL && !_ident->_names.empty() && !_ident->_names.back().has_templ()) {
           if (rep->is_template()) {
           if (rep->is_template()) {
             rep->_template_scope = (CPPTemplateScope *)NULL;
             rep->_template_scope = (CPPTemplateScope *)NULL;
             CPPNameComponent nc(get_simple_name());
             CPPNameComponent nc(get_simple_name());

+ 10 - 0
dtool/src/cppparser/cppTemplateScope.cxx

@@ -49,6 +49,16 @@ add_enum_value(CPPInstance *inst) {
   _parent_scope->add_enum_value(inst);
   _parent_scope->add_enum_value(inst);
 }
 }
 
 
+/**
+ *
+ */
+void CPPTemplateScope::
+define_typedef_type(CPPTypedefType *type, CPPPreprocessor *error_sink) {
+  type->_template_scope = this;
+  assert(_parent_scope != NULL);
+  _parent_scope->define_typedef_type(type, error_sink);
+}
+
 /**
 /**
  *
  *
  */
  */

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

@@ -34,6 +34,8 @@ public:
                                CPPPreprocessor *preprocessor,
                                CPPPreprocessor *preprocessor,
                                const cppyyltype &pos);
                                const cppyyltype &pos);
   virtual void add_enum_value(CPPInstance *inst);
   virtual void add_enum_value(CPPInstance *inst);
+  virtual void define_typedef_type(CPPTypedefType *type,
+                                   CPPPreprocessor *error_sink = NULL);
   virtual void define_extension_type(CPPExtensionType *type,
   virtual void define_extension_type(CPPExtensionType *type,
                                      CPPPreprocessor *error_sink = NULL);
                                      CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void define_namespace(CPPNamespace *scope);

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

@@ -14,6 +14,8 @@
 #include "cppTypedefType.h"
 #include "cppTypedefType.h"
 #include "cppIdentifier.h"
 #include "cppIdentifier.h"
 #include "cppInstanceIdentifier.h"
 #include "cppInstanceIdentifier.h"
+#include "cppTemplateScope.h"
+#include "indent.h"
 
 
 /**
 /**
  *
  *
@@ -193,6 +195,17 @@ is_fully_specified() const {
     _type->is_fully_specified();
     _type->is_fully_specified();
 }
 }
 
 
+/**
+ *
+ */
+CPPDeclaration *CPPTypedefType::
+instantiate(const CPPTemplateParameterList *actual_params,
+            CPPScope *current_scope, CPPScope *global_scope,
+            CPPPreprocessor *error_sink) const {
+
+  return _type->instantiate(actual_params, current_scope, global_scope, error_sink);
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -320,6 +333,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
   if (complete) {
   if (complete) {
     if (_using) {
     if (_using) {
       // It was declared using the "using" keyword.
       // It was declared using the "using" keyword.
+      if (is_template()) {
+        get_template_scope()->_parameters.write_formal(out, scope);
+        indent(out, indent_level);
+      }
       out << "using " << name << " = ";
       out << "using " << name << " = ";
       _type->output(out, 0, scope, false);
       _type->output(out, 0, scope, false);
     } else {
     } else {

+ 8 - 1
dtool/src/cppparser/cppTypedefType.h

@@ -21,7 +21,9 @@ class CPPIdentifier;
 class CPPInstanceIdentifier;
 class CPPInstanceIdentifier;
 
 
 /**
 /**
- *
+ * A type alias created by a C++ typedef or using declaration.  These aren't
+ * officially supposed to be types in themselves, but we represent them as
+ * such so that we can preserve typedef names in the generated code.
  */
  */
 class CPPTypedefType : public CPPType {
 class CPPTypedefType : public CPPType {
 public:
 public:
@@ -46,6 +48,11 @@ public:
 
 
   virtual bool is_fully_specified() const;
   virtual bool is_fully_specified() const;
 
 
+  virtual CPPDeclaration *
+  instantiate(const CPPTemplateParameterList *actual_params,
+              CPPScope *current_scope, CPPScope *global_scope,
+              CPPPreprocessor *error_sink = NULL) const;
+
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
                                           CPPScope *global_scope);

+ 0 - 534
dtool/src/dtoolbase/dlmalloc.h

@@ -1,534 +0,0 @@
-/*
-  Default header file for malloc-2.8.x, written by Doug Lea
-  and released to the public domain, as explained at
-  http://creativecommons.org/licenses/publicdomain. 
- 
-  last update: Mon Aug 15 08:55:52 2005  Doug Lea  (dl at gee)
-
-  This header is for ANSI C/C++ only.  You can set any of
-  the following #defines before including:
-
-  * If USE_DL_PREFIX is defined, it is assumed that malloc.c 
-    was also compiled with this option, so all routines
-    have names starting with "dl".
-
-  * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
-    file will be #included AFTER <malloc.h>. This is needed only if
-    your system defines a struct mallinfo that is incompatible with the
-    standard one declared here.  Otherwise, you can include this file
-    INSTEAD of your system system <malloc.h>.  At least on ANSI, all
-    declarations should be compatible with system versions
-
-  * If MSPACES is defined, declarations for mspace versions are included.
-*/
-
-#ifndef MALLOC_280_H
-#define MALLOC_280_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>   /* for size_t */
-
-#if !ONLY_MSPACES
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc               calloc
-#define dlfree                 free
-#define dlmalloc               malloc
-#define dlmemalign             memalign
-#define dlrealloc              realloc
-#define dlvalloc               valloc
-#define dlpvalloc              pvalloc
-#define dlmallinfo             mallinfo
-#define dlmallopt              mallopt
-#define dlmalloc_trim          malloc_trim
-#define dlmalloc_stats         malloc_stats
-#define dlmalloc_usable_size   malloc_usable_size
-#define dlmalloc_footprint     malloc_footprint
-#define dlindependent_calloc   independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#endif /* USE_DL_PREFIX */
-
-
-/*
-  malloc(size_t n)
-  Returns a pointer to a newly allocated chunk of at least n bytes, or
-  null if no space is available, in which case errno is set to ENOMEM
-  on ANSI C systems.
-
-  If n is zero, malloc returns a minimum-sized chunk. (The minimum
-  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
-  systems.)  Note that size_t is an unsigned type, so calls with
-  arguments that would be negative if signed are interpreted as
-  requests for huge amounts of space, which will often fail. The
-  maximum supported value of n differs across systems, but is in all
-  cases less than the maximum representable value of a size_t.
-*/
-void* dlmalloc(size_t);
-
-/*
-  free(void* p)
-  Releases the chunk of memory pointed to by p, that had been previously
-  allocated using malloc or a related routine such as realloc.
-  It has no effect if p is null. If p was not malloced or already
-  freed, free(p) will by default cuase the current program to abort.
-*/
-void  dlfree(void*);
-
-/*
-  calloc(size_t n_elements, size_t element_size);
-  Returns a pointer to n_elements * element_size bytes, with all locations
-  set to zero.
-*/
-void* dlcalloc(size_t, size_t);
-
-/*
-  realloc(void* p, size_t n)
-  Returns a pointer to a chunk of size n that contains the same data
-  as does chunk p up to the minimum of (n, p's size) bytes, or null
-  if no space is available.
-
-  The returned pointer may or may not be the same as p. The algorithm
-  prefers extending p in most cases when possible, otherwise it
-  employs the equivalent of a malloc-copy-free sequence.
-
-  If p is null, realloc is equivalent to malloc.
-
-  If space is not available, realloc returns null, errno is set (if on
-  ANSI) and p is NOT freed.
-
-  if n is for fewer bytes than already held by p, the newly unused
-  space is lopped off and freed if possible.  realloc with a size
-  argument of zero (re)allocates a minimum-sized chunk.
-
-  The old unix realloc convention of allowing the last-free'd chunk
-  to be used as an argument to realloc is not supported.
-*/
-
-void* dlrealloc(void*, size_t);
-
-/*
-  memalign(size_t alignment, size_t n);
-  Returns a pointer to a newly allocated chunk of n bytes, aligned
-  in accord with the alignment argument.
-
-  The alignment argument should be a power of two. If the argument is
-  not a power of two, the nearest greater power is used.
-  8-byte alignment is guaranteed by normal malloc calls, so don't
-  bother calling memalign with an argument of 8 or less.
-
-  Overreliance on memalign is a sure way to fragment space.
-*/
-void* dlmemalign(size_t, size_t);
-
-/*
-  valloc(size_t n);
-  Equivalent to memalign(pagesize, n), where pagesize is the page
-  size of the system. If the pagesize is unknown, 4096 is used.
-*/
-void* dlvalloc(size_t);
-
-/*
-  mallopt(int parameter_number, int parameter_value)
-  Sets tunable parameters The format is to provide a
-  (parameter-number, parameter-value) pair.  mallopt then sets the
-  corresponding parameter to the argument value if it can (i.e., so
-  long as the value is meaningful), and returns 1 if successful else
-  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
-  normally defined in malloc.h.  None of these are use in this malloc,
-  so setting them has no effect. But this malloc also supports other
-  options in mallopt:
-
-  Symbol            param #  default    allowed param values
-  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1U disables trimming)
-  M_GRANULARITY        -2     page size   any power of 2 >= page size
-  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
-*/
-int dlmallopt(int, int);
-
-#ifndef M_TRIM_THRESHOLD
-#define M_TRIM_THRESHOLD     (-1)
-#endif
-#ifndef M_GRANULARITY
-#define M_GRANULARITY        (-2)
-#endif
-#ifndef M_MMAP_THRESHOLD
-#define M_MMAP_THRESHOLD     (-3)
-#endif
-
-/*
-  malloc_footprint();
-  Returns the number of bytes obtained from the system.  The total
-  number of bytes allocated by malloc, realloc etc., is less than this
-  value. Unlike mallinfo, this function returns only a precomputed
-  result, so can be called frequently to monitor memory consumption.
-  Even if locks are otherwise defined, this function does not use them,
-  so results might not be up to date.
-*/
-size_t dlmalloc_footprint();
-
-#if !NO_MALLINFO
-/*
-  mallinfo()
-  Returns (by copy) a struct containing various summary statistics:
-
-  arena:     current total non-mmapped bytes allocated from system
-  ordblks:   the number of free chunks
-  smblks:    always zero.
-  hblks:     current number of mmapped regions
-  hblkhd:    total bytes held in mmapped regions
-  usmblks:   the maximum total allocated space. This will be greater
-                than current total if trimming has occurred.
-  fsmblks:   always zero
-  uordblks:  current total allocated space (normal or mmapped)
-  fordblks:  total free space
-  keepcost:  the maximum number of bytes that could ideally be released
-               back to system via malloc_trim. ("ideally" means that
-               it ignores page restrictions etc.)
-
-  Because these fields are ints, but internal bookkeeping may
-  be kept as longs, the reported values may wrap around zero and
-  thus be inaccurate.
-*/
-#ifndef HAVE_USR_INCLUDE_MALLOC_H
-#ifndef _MALLOC_H
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif /* MALLINFO_FIELD_TYPE */
-struct mallinfo {
-  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
-  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
-  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
-  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
-  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
-  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
-  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
-  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
-  MALLINFO_FIELD_TYPE fordblks; /* total free space */
-  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif  /* _MALLOC_H */
-#endif  /* HAVE_USR_INCLUDE_MALLOC_H */
-
-struct mallinfo dlmallinfo(void);
-#endif  /* NO_MALLINFO */
-
-/*
-  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
-  independent_calloc is similar to calloc, but instead of returning a
-  single cleared space, it returns an array of pointers to n_elements
-  independent elements that can hold contents of size elem_size, each
-  of which starts out cleared, and can be independently freed,
-  realloc'ed etc. The elements are guaranteed to be adjacently
-  allocated (this is not guaranteed to occur with multiple callocs or
-  mallocs), which may also improve cache locality in some
-  applications.
-
-  The "chunks" argument is optional (i.e., may be null, which is
-  probably the most typical usage). If it is null, the returned array
-  is itself dynamically allocated and should also be freed when it is
-  no longer needed. Otherwise, the chunks array must be of at least
-  n_elements in length. It is filled in with the pointers to the
-  chunks.
-
-  In either case, independent_calloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and "chunks"
-  is null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be individually freed when it is no longer
-  needed. If you'd like to instead be able to free all at once, you
-  should instead use regular calloc and assign pointers into this
-  space to represent elements.  (In this case though, you cannot
-  independently free elements.)
-
-  independent_calloc simplifies and speeds up implementations of many
-  kinds of pools.  It may also be useful when constructing large data
-  structures that initially have a fixed number of fixed-sized nodes,
-  but the number is not known at compile time, and some of the nodes
-  may later need to be freed. For example:
-
-  struct Node { int item; struct Node* next; };
-
-  struct Node* build_list() {
-    struct Node** pool;
-    int n = read_number_of_nodes_needed();
-    if (n <= 0) return 0;
-    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
-    if (pool == 0) die();
-    // organize into a linked list...
-    struct Node* first = pool[0];
-    for (i = 0; i < n-1; ++i)
-      pool[i]->next = pool[i+1];
-    free(pool);     // Can now free the array (or not, if it is needed later)
-    return first;
-  }
-*/
-void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
-  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
-  independent_comalloc allocates, all at once, a set of n_elements
-  chunks with sizes indicated in the "sizes" array.    It returns
-  an array of pointers to these elements, each of which can be
-  independently freed, realloc'ed etc. The elements are guaranteed to
-  be adjacently allocated (this is not guaranteed to occur with
-  multiple callocs or mallocs), which may also improve cache locality
-  in some applications.
-
-  The "chunks" argument is optional (i.e., may be null). If it is null
-  the returned array is itself dynamically allocated and should also
-  be freed when it is no longer needed. Otherwise, the chunks array
-  must be of at least n_elements in length. It is filled in with the
-  pointers to the chunks.
-
-  In either case, independent_comalloc returns this pointer array, or
-  null if the allocation failed.  If n_elements is zero and chunks is
-  null, it returns a chunk representing an array with zero elements
-  (which should be freed if not wanted).
-
-  Each element must be individually freed when it is no longer
-  needed. If you'd like to instead be able to free all at once, you
-  should instead use a single regular malloc, and assign pointers at
-  particular offsets in the aggregate space. (In this case though, you
-  cannot independently free elements.)
-
-  independent_comallac differs from independent_calloc in that each
-  element may have a different size, and also that it does not
-  automatically clear elements.
-
-  independent_comalloc can be used to speed up allocation in cases
-  where several structs or objects must always be allocated at the
-  same time.  For example:
-
-  struct Head { ... }
-  struct Foot { ... }
-
-  void send_message(char* msg) {
-    int msglen = strlen(msg);
-    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
-    void* chunks[3];
-    if (independent_comalloc(3, sizes, chunks) == 0)
-      die();
-    struct Head* head = (struct Head*)(chunks[0]);
-    char*        body = (char*)(chunks[1]);
-    struct Foot* foot = (struct Foot*)(chunks[2]);
-    // ...
-  }
-
-  In general though, independent_comalloc is worth using only for
-  larger values of n_elements. For small values, you probably won't
-  detect enough difference from series of malloc calls to bother.
-
-  Overuse of independent_comalloc can increase overall memory usage,
-  since it cannot reuse existing noncontiguous small chunks that
-  might be available for some of the elements.
-*/
-void** dlindependent_comalloc(size_t, size_t*, void**);
-
-
-/*
-  pvalloc(size_t n);
-  Equivalent to valloc(minimum-page-that-holds(n)), that is,
-  round up n to nearest pagesize.
- */
-void*  dlpvalloc(size_t);
-
-/*
-  malloc_trim(size_t pad);
-
-  If possible, gives memory back to the system (via negative arguments
-  to sbrk) if there is unused memory at the `high' end of the malloc
-  pool or in unused MMAP segments. You can call this after freeing
-  large blocks of memory to potentially reduce the system-level memory
-  requirements of a program. However, it cannot guarantee to reduce
-  memory. Under some allocation patterns, some large free blocks of
-  memory will be locked between two used chunks, so they cannot be
-  given back to the system.
-
-  The `pad' argument to malloc_trim represents the amount of free
-  trailing space to leave untrimmed. If this argument is zero, only
-  the minimum amount of memory to maintain internal data structures
-  will be left. Non-zero arguments can be supplied to maintain enough
-  trailing space to service future expected allocations without having
-  to re-obtain memory from the system.
-
-  Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-int  dlmalloc_trim(size_t);
-
-/*
-  malloc_usable_size(void* p);
-
-  Returns the number of bytes you can actually use in
-  an allocated chunk, which may be more than you requested (although
-  often not) due to alignment and minimum size constraints.
-  You can use this many bytes without worrying about
-  overwriting other allocated objects. This is not a particularly great
-  programming practice. malloc_usable_size can be more useful in
-  debugging and assertions, for example:
-
-  p = malloc(n);
-  assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(void*);
-
-/*
-  malloc_stats();
-  Prints on stderr the amount of space obtained from the system (both
-  via sbrk and mmap), the maximum amount (which may be more than
-  current if malloc_trim and/or munmap got called), and the current
-  number of bytes allocated via malloc (or realloc, etc) but not yet
-  freed. Note that this is the number of bytes allocated, not the
-  number requested. It will be larger than the number requested
-  because of alignment and bookkeeping overhead. Because it includes
-  alignment wastage as being in use, this figure may be greater than
-  zero even when no user-level chunks are allocated.
-
-  The reported current and maximum system memory can be inaccurate if
-  a program makes other calls to system memory allocation functions
-  (normally sbrk) outside of malloc.
-
-  malloc_stats prints only the most commonly interesting statistics.
-  More information can be obtained by calling mallinfo.
-*/
-void  dlmalloc_stats();
-
-#endif /* !ONLY_MSPACES */
-
-#if MSPACES
-
-/*
-  mspace is an opaque type representing an independent
-  region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
-  create_mspace creates and returns a new independent space with the
-  given initial capacity, or, if 0, the default granularity size.  It
-  returns null if there is no system memory available to create the
-  space.  If argument locked is non-zero, the space uses a separate
-  lock to control access. The capacity of the space will grow
-  dynamically as needed to service mspace_malloc requests.  You can
-  control the sizes of incremental increases of this space by
-  compiling with a different DEFAULT_GRANULARITY or dynamically
-  setting with mallopt(M_GRANULARITY, value).
-*/
-mspace create_mspace(size_t capacity, int locked);
-
-/*
-  destroy_mspace destroys the given space, and attempts to return all
-  of its memory back to the system, returning the total number of
-  bytes freed. After destruction, the results of access to all memory
-  used by the space become undefined.
-*/
-size_t destroy_mspace(mspace msp);
-
-/*
-  create_mspace_with_base uses the memory supplied as the initial base
-  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
-  space is used for bookkeeping, so the capacity must be at least this
-  large. (Otherwise 0 is returned.) When this initial space is
-  exhausted, additional memory will be obtained from the system.
-  Destroying this space will deallocate all additionally allocated
-  space (if possible) but not the initial base.
-*/
-mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
-  mspace_malloc behaves as malloc, but operates within
-  the given space.
-*/
-void* mspace_malloc(mspace msp, size_t bytes);
-
-/*
-  mspace_free behaves as free, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_free is not actually needed.
-  free may be called instead of mspace_free because freed chunks from
-  any space are handled by their originating spaces.
-*/
-void mspace_free(mspace msp, void* mem);
-
-/*
-  mspace_realloc behaves as realloc, but operates within
-  the given space.
-
-  If compiled with FOOTERS==1, mspace_realloc is not actually
-  needed.  realloc may be called instead of mspace_realloc because
-  realloced chunks from any space are handled by their originating
-  spaces.
-*/
-void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-
-/*
-  mspace_calloc behaves as calloc, but operates within
-  the given space.
-*/
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-
-/*
-  mspace_memalign behaves as memalign, but operates within
-  the given space.
-*/
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-
-/*
-  mspace_independent_calloc behaves as independent_calloc, but
-  operates within the given space.
-*/
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
-                                 size_t elem_size, void* chunks[]);
-
-/*
-  mspace_independent_comalloc behaves as independent_comalloc, but
-  operates within the given space.
-*/
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
-                                   size_t sizes[], void* chunks[]);
-
-/*
-  mspace_footprint() returns the number of bytes obtained from the
-  system for this space.
-*/
-size_t mspace_footprint(mspace msp);
-
-
-#if !NO_MALLINFO
-/*
-  mspace_mallinfo behaves as mallinfo, but reports properties of
-  the given space.
-*/
-struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
-  mspace_malloc_stats behaves as malloc_stats, but reports
-  properties of the given space.
-*/
-void mspace_malloc_stats(mspace msp);
-
-/*
-  mspace_trim behaves as malloc_trim, but
-  operates within the given space.
-*/
-int mspace_trim(mspace msp, size_t pad);
-
-/*
-  An alias for mallopt.
-*/
-int mspace_mallopt(int, int);
-
-#endif  /* MSPACES */
-
-#ifdef __cplusplus
-};  /* end of extern "C" */
-#endif
-
-#endif /* MALLOC_280_H */

File diff suppressed because it is too large
+ 405 - 130
dtool/src/dtoolbase/dlmalloc_src.cxx


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

@@ -416,7 +416,6 @@ typedef struct _object PyObject;
 #define MAKE_PROPERTY2(property_name, ...) __make_property2(property_name, __VA_ARGS__)
 #define MAKE_PROPERTY2(property_name, ...) __make_property2(property_name, __VA_ARGS__)
 #define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
 #define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
 #define MAKE_SEQ_PROPERTY(property_name, ...) __make_seq_property(property_name, __VA_ARGS__)
 #define MAKE_SEQ_PROPERTY(property_name, ...) __make_seq_property(property_name, __VA_ARGS__)
-#undef USE_STL_ALLOCATOR  /* Don't try to parse these template classes in interrogate. */
 #define EXTENSION(x) __extension x
 #define EXTENSION(x) __extension x
 #define EXTEND __extension
 #define EXTEND __extension
 #else
 #else

+ 7 - 4
dtool/src/dtoolbase/memoryHook.cxx

@@ -43,16 +43,19 @@
 // fast, but it is not thread-safe.  However, we provide thread locking within
 // fast, but it is not thread-safe.  However, we provide thread locking within
 // MemoryHook.
 // MemoryHook.
 
 
+#define DLMALLOC_EXPORT static
 #define USE_DL_PREFIX 1
 #define USE_DL_PREFIX 1
 #define NO_MALLINFO 1
 #define NO_MALLINFO 1
 #ifdef _DEBUG
 #ifdef _DEBUG
   #define DEBUG 1
   #define DEBUG 1
 #endif
 #endif
-#ifdef assert
-  // dlmalloc defines its own assert, which clashes.
-  #undef assert
+#ifdef LINMATH_ALIGN
+// drose: 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.
+#define MALLOC_ALIGNMENT ((size_t)16U)
 #endif
 #endif
-#include "dlmalloc.h"
+
 #include "dlmalloc_src.cxx"
 #include "dlmalloc_src.cxx"
 
 
 #define call_malloc dlmalloc
 #define call_malloc dlmalloc

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

@@ -32,7 +32,7 @@
  * can allocate arrays of objects.
  * can allocate arrays of objects.
  */
  */
 
 
-#ifndef USE_STL_ALLOCATOR
+#if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER)
 // If we're not trying to make custom allocators (either we don't know what
 // If we're not trying to make custom allocators (either we don't know what
 // kind of syntax this STL library wants, or we're compiling with OPTIMIZE 4),
 // kind of syntax this STL library wants, or we're compiling with OPTIMIZE 4),
 // then simply use the standard allocator.
 // then simply use the standard allocator.

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

@@ -19,7 +19,7 @@
 #include "register_type.h"
 #include "register_type.h"
 #include <deque>
 #include <deque>
 
 
-#ifndef USE_STL_ALLOCATOR
+#if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER)
 // If we're not using custom allocators, just use the standard class
 // If we're not using custom allocators, just use the standard class
 // definition.
 // definition.
 #define pdeque deque
 #define pdeque deque

+ 1 - 1
dtool/src/dtoolbase/pdtoa.cxx

@@ -250,7 +250,7 @@ inline static unsigned CountDecimalDigit32(uint32_t n) {
 }
 }
 
 
 inline static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
 inline static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
-  static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+  static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 0, 0, 0, 0, 0 };
   const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
   const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
   const DiyFp wp_w = Mp - W;
   const DiyFp wp_w = Mp - W;
   uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
   uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);

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

@@ -19,7 +19,7 @@
 #include "register_type.h"
 #include "register_type.h"
 #include <list>
 #include <list>
 
 
-#ifndef USE_STL_ALLOCATOR
+#if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER)
 // If we're not using custom allocators, just use the standard class
 // If we're not using custom allocators, just use the standard class
 // definition.
 // definition.
 #define plist list
 #define plist list

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

@@ -24,7 +24,7 @@
 #include <hash_map>
 #include <hash_map>
 #endif
 #endif
 
 
-#ifndef USE_STL_ALLOCATOR
+#if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER)
 // If we're not using custom allocators, just use the standard class
 // If we're not using custom allocators, just use the standard class
 // definition.
 // definition.
 #define pmap map
 #define pmap map

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

@@ -24,7 +24,7 @@
 #include <hash_set>
 #include <hash_set>
 #endif
 #endif
 
 
-#ifndef USE_STL_ALLOCATOR
+#if !defined(USE_STL_ALLOCATOR) || defined(CPPPARSER)
 // If we're not using custom allocators, just use the standard class
 // If we're not using custom allocators, just use the standard class
 // definition.
 // definition.
 #define pset set
 #define pset set

+ 6 - 0
dtool/src/dtoolbase/pvector.h

@@ -25,6 +25,12 @@
 // definition.
 // definition.
 #define pvector vector
 #define pvector vector
 
 
+#elif defined(CPPPARSER)
+// Simplified definition to speed up Interrogate parsing.
+template<class Type>
+class pvector : public vector<Type> {
+};
+
 #else
 #else
 
 
 /**
 /**

+ 5 - 1
dtool/src/dtoolutil/filename.cxx

@@ -443,7 +443,11 @@ temporary(const string &dirname, const string &prefix, const string &suffix,
     // generate a 6-character hex code.
     // generate a 6-character hex code.
     int hash = (clock() * time(NULL)) & 0xffffff;
     int hash = (clock() * time(NULL)) & 0xffffff;
     char hex_code[10];
     char hex_code[10];
-    sprintf(hex_code, "%06x", hash);
+#ifdef _WIN32
+    sprintf_s(hex_code, 10, "%06x", hash);
+#else
+    snprintf(hex_code, 10, "%06x", hash);
+#endif
     result = Filename(fdirname, Filename(prefix + hex_code + suffix));
     result = Filename(fdirname, Filename(prefix + hex_code + suffix));
     result.set_type(type);
     result.set_type(type);
   } while (result.exists());
   } while (result.exists());

+ 14 - 1
dtool/src/interrogate/interfaceMaker.cxx

@@ -133,7 +133,8 @@ check_protocols() {
     if (func->_ifunc.get_name() == "__traverse__") {
     if (func->_ifunc.get_name() == "__traverse__") {
       // If we have a method named __traverse__, we implement Python's cyclic
       // If we have a method named __traverse__, we implement Python's cyclic
       // garbage collection protocol.
       // garbage collection protocol.
-      _protocol_types |= PT_python_gc;
+      //XXX disabled for now because it's too unstable.
+      //_protocol_types |= PT_python_gc;
     }
     }
   }
   }
 
 
@@ -361,6 +362,18 @@ remap_parameter(CPPType *struct_type, CPPType *param_type) {
         }
         }
       }
       }
     }
     }
+    if (struct_type == (CPPType *)NULL ||
+        !TypeManager::is_vector_unsigned_char(struct_type)) {
+      if (TypeManager::is_vector_unsigned_char(param_type)) {
+        if (TypeManager::is_reference(param_type)) {
+          return new ParameterRemapReferenceToConcrete(param_type);
+        } else if (TypeManager::is_const(param_type)) {
+          return new ParameterRemapConstToNonConst(param_type);
+        } else {
+          return new ParameterRemapUnchanged(param_type);
+        }
+      }
+    }
   }
   }
 
 
   if (manage_reference_counts) {
   if (manage_reference_counts) {

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

@@ -2890,10 +2890,12 @@ write_module_class(ostream &out, Object *obj) {
   }
   }
 
 
   // traverseproc tp_traverse;
   // traverseproc tp_traverse;
-  write_function_slot(out, 4, slots, "tp_traverse");
+  out << "    0, // tp_traverse\n";
+  //write_function_slot(out, 4, slots, "tp_traverse");
 
 
   // inquiry tp_clear;
   // inquiry tp_clear;
-  write_function_slot(out, 4, slots, "tp_clear");
+  out << "    0, // tp_clear\n";
+  //write_function_slot(out, 4, slots, "tp_clear");
 
 
   // richcmpfunc tp_richcompare;
   // richcmpfunc tp_richcompare;
   if (has_local_richcompare) {
   if (has_local_richcompare) {
@@ -4794,6 +4796,26 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       clear_error = true;
       clear_error = true;
       only_pyobjects = false;
       only_pyobjects = false;
 
 
+    } else if (TypeManager::is_vector_unsigned_char(type)) {
+      indent(out, indent_level) << "unsigned char *" << param_name << "_str = NULL;\n";
+      indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n";
+
+      if (args_type == AT_single_arg) {
+        extra_param_check << " && PyBytes_AsStringAndSize(arg, (char **)&"
+          << param_name << "_str, &" << param_name << "_len) >= 0";
+      } else {
+        format_specifiers += "\" FMTCHAR_BYTES \"#";
+        parameter_list += ", &" + param_name + "_str, &" + param_name + "_len";
+      }
+
+      pexpr_string = type->get_local_name(&parser);
+      pexpr_string += "(" + param_name + "_str, " + param_name + "_str + " + param_name + "_len" + ")";
+      expected_params += "bytes";
+
+      // Remember to clear the TypeError that any of the above methods raise.
+      clear_error = true;
+      only_pyobjects = false;
+
     } else if (TypeManager::is_bool(type)) {
     } else if (TypeManager::is_bool(type)) {
       if (args_type == AT_single_arg) {
       if (args_type == AT_single_arg) {
         param_name = "arg";
         param_name = "arg";
@@ -6072,7 +6094,8 @@ pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,
       TypeManager::is_char_pointer(type) ||
       TypeManager::is_char_pointer(type) ||
       TypeManager::is_wchar_pointer(type) ||
       TypeManager::is_wchar_pointer(type) ||
       TypeManager::is_pointer_to_PyObject(type) ||
       TypeManager::is_pointer_to_PyObject(type) ||
-      TypeManager::is_pointer_to_Py_buffer(type)) {
+      TypeManager::is_pointer_to_Py_buffer(type) ||
+      TypeManager::is_vector_unsigned_char(type)) {
     // Most types are now handled by the many overloads of Dtool_WrapValue,
     // Most types are now handled by the many overloads of Dtool_WrapValue,
     // defined in py_panda.h.
     // defined in py_panda.h.
     indent(out, indent_level)
     indent(out, indent_level)
@@ -6241,7 +6264,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
       out <<
       out <<
         "  " << cClassName  << " *local_this = NULL;\n"
         "  " << cClassName  << " *local_this = NULL;\n"
         "  if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
         "  if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
-        "    return NULL;\n"
+        "    return -1;\n"
         "  }\n"
         "  }\n"
         "  return (Py_ssize_t)" << len_remap->get_call_str("local_this", pexprs) << ";\n";
         "  return (Py_ssize_t)" << len_remap->get_call_str("local_this", pexprs) << ";\n";
     } else {
     } else {
@@ -6713,6 +6736,8 @@ is_cpp_type_legal(CPPType *in_ctype) {
     return true;
     return true;
   } else if (TypeManager::is_basic_string_wchar(type)) {
   } else if (TypeManager::is_basic_string_wchar(type)) {
     return true;
     return true;
+  } else if (TypeManager::is_vector_unsigned_char(type)) {
+    return true;
   } else if (TypeManager::is_simple(type)) {
   } else if (TypeManager::is_simple(type)) {
     return true;
     return true;
   } else if (TypeManager::is_pointer_to_simple(type)) {
   } else if (TypeManager::is_pointer_to_simple(type)) {

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

@@ -1167,8 +1167,10 @@ scan_typedef_type(CPPTypedefType *type) {
     return;
     return;
   }
   }
 
 
-  // A typedef cannot be a template declaration.
-  assert(!type->is_template());
+  if (type->is_template()) {
+    // The type is a template declaration, not a true type.
+    return;
+  }
 
 
   if (type->_file.is_c_file()) {
   if (type->_file.is_c_file()) {
     // This type declaration appears in a .C file.  We can only export types
     // This type declaration appears in a .C file.  We can only export types

+ 60 - 0
dtool/src/interrogate/typeManager.cxx

@@ -937,6 +937,66 @@ is_wstring(CPPType *type) {
   return is_basic_string_wchar(type);
   return is_basic_string_wchar(type);
 }
 }
 
 
+/**
+ * Returns true if the type is vector<unsigned char>, or a const reference to
+ * it.
+ */
+bool TypeManager::
+is_vector_unsigned_char(CPPType *type) {
+  if (type->get_local_name(&parser) == "vector< unsigned char >" ||
+      type->get_local_name(&parser) == "pvector< unsigned char >") {
+    return true;
+  }
+
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_vector_unsigned_char(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_reference:
+    return is_const_vector_unsigned_char(type->as_reference_type()->_pointing_at);
+
+  case CPPDeclaration::ST_struct:
+    {
+      CPPStructType *stype = type->as_struct_type();
+      CPPStructType::Derivation::const_iterator di;
+      for (di = stype->_derivation.begin();
+           di != stype->_derivation.end();
+           ++di) {
+        if (is_vector_unsigned_char((*di)._base)) {
+          return true;
+        }
+      }
+    }
+    break;
+
+  case CPPDeclaration::ST_typedef:
+    return is_vector_unsigned_char(type->as_typedef_type()->_type);
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
+/**
+ * Returns true if the indicated type is a const wrapper around
+ * vector<unsigned char>.
+ */
+bool TypeManager::
+is_const_vector_unsigned_char(CPPType *type) {
+  switch (type->get_subtype()) {
+  case CPPDeclaration::ST_const:
+    return is_vector_unsigned_char(type->as_const_type()->_wrapped_around);
+
+  case CPPDeclaration::ST_typedef:
+    return is_const_vector_unsigned_char(type->as_typedef_type()->_type);
+
+  default:
+    return false;
+  }
+}
+
 /**
 /**
  * Returns true if the indicated type is bool, or some trivial variant.
  * Returns true if the indicated type is bool, or some trivial variant.
  */
  */

+ 2 - 0
dtool/src/interrogate/typeManager.h

@@ -81,6 +81,8 @@ public:
   static bool is_const_ref_to_basic_string_wchar(CPPType *type);
   static bool is_const_ref_to_basic_string_wchar(CPPType *type);
   static bool is_const_ptr_to_basic_string_wchar(CPPType *type);
   static bool is_const_ptr_to_basic_string_wchar(CPPType *type);
   static bool is_wstring(CPPType *type);
   static bool is_wstring(CPPType *type);
+  static bool is_vector_unsigned_char(CPPType *type);
+  static bool is_const_vector_unsigned_char(CPPType *type);
   static bool is_pair(CPPType *type);
   static bool is_pair(CPPType *type);
   static bool is_bool(CPPType *type);
   static bool is_bool(CPPType *type);
   static bool is_integer(CPPType *type);
   static bool is_integer(CPPType *type);

+ 4 - 0
dtool/src/interrogatedb/interrogate_request.cxx

@@ -20,7 +20,11 @@ void
 interrogate_request_database(const char *database_filename) {
 interrogate_request_database(const char *database_filename) {
   InterrogateModuleDef *def = new InterrogateModuleDef;
   InterrogateModuleDef *def = new InterrogateModuleDef;
   memset(def, 0, sizeof(InterrogateModuleDef));
   memset(def, 0, sizeof(InterrogateModuleDef));
+#ifdef _WIN32
+  def->database_filename = _strdup(database_filename);
+#else
   def->database_filename = strdup(database_filename);
   def->database_filename = strdup(database_filename);
+#endif
 
 
   // Don't think of this as a leak; think of it as a one-time database
   // Don't think of this as a leak; think of it as a one-time database
   // allocation.
   // allocation.

+ 2 - 4
dtool/src/interrogatedb/py_panda.cxx

@@ -67,7 +67,7 @@ void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *c
  * was of the wrong type, raises an AttributeError.
  * was of the wrong type, raises an AttributeError.
  */
  */
 bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer) {
 bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer) {
-  if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
+  if (self == NULL || !DtoolCanThisBeAPandaInstance(self) || ((Dtool_PyInstDef *)self)->_ptr_to_object == NULL) {
     Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
     Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
     return false;
     return false;
   }
   }
@@ -87,7 +87,7 @@ bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef
 bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
 bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
                                             void **answer, const char *method_name) {
                                             void **answer, const char *method_name) {
 
 
-  if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
+  if (self == NULL || !DtoolCanThisBeAPandaInstance(self) || ((Dtool_PyInstDef *)self)->_ptr_to_object == NULL) {
     Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
     Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
     return false;
     return false;
   }
   }
@@ -172,7 +172,6 @@ void *DTOOL_Call_GetPointerThis(PyObject *self) {
   return NULL;
   return NULL;
 }
 }
 
 
-#ifndef NDEBUG
 /**
 /**
  * This is similar to a PyErr_Occurred() check, except that it also checks
  * This is similar to a PyErr_Occurred() check, except that it also checks
  * Notify to see if an assertion has occurred.  If that is the case, then it
  * Notify to see if an assertion has occurred.  If that is the case, then it
@@ -193,7 +192,6 @@ bool _Dtool_CheckErrorOccurred() {
   }
   }
   return false;
   return false;
 }
 }
-#endif  // NDEBUG
 
 
 /**
 /**
  * Raises an AssertionError containing the last thrown assert message, and
  * Raises an AssertionError containing the last thrown assert message, and

+ 7 - 0
dtool/src/interrogatedb/py_panda.h

@@ -128,6 +128,13 @@ typedef long Py_hash_t;
 #endif
 #endif
 #endif
 #endif
 
 
+// Which character to use in PyArg_ParseTuple et al for a byte string.
+#if PY_MAJOR_VERSION >= 3
+#define FMTCHAR_BYTES "y"
+#else
+#define FMTCHAR_BYTES "s"
+#endif
+
 using namespace std;
 using namespace std;
 
 
 // this is tempory .. untill this is glued better into the panda build system
 // this is tempory .. untill this is glued better into the panda build system

+ 17 - 0
dtool/src/parser-inc/netinet/in.h

@@ -0,0 +1,17 @@
+#include <stdint.h>
+#include <sys/socket.h>
+
+typedef uint32_t in_addr_t;
+struct in_addr;
+typedef uint16_t in_port_t;
+struct in6_addr;
+struct sockaddr_in;
+struct sockaddr_in6;
+struct ip_mreq;
+struct ip_mreq_source;
+struct ipv6_mreq;
+struct group_req;
+struct group_source_req;
+struct ip_msfilter;
+struct group_filter;
+

+ 0 - 10
dtool/src/parser-inc/socket.h

@@ -1,10 +0,0 @@
-typedef int SOCKET ;
-
-struct sockaddr_in
-{
-};
-
-typedef struct fd_set {
-        unsigned int fd_count;               /* how many are SET? */
-        SOCKET  fd_array[10];   /* an array of SOCKETs */
-} fd_set;

+ 18 - 0
dtool/src/parser-inc/sys/socket.h

@@ -0,0 +1,18 @@
+#pragma once
+
+typedef int socklen_t;
+typedef unsigned short int sa_family_t;
+
+struct sockaddr {
+  sa_family_t sa_family;
+  char sa_data[];
+};
+
+struct sockaddr_storage {
+  sa_family_t ss_family;
+};
+
+typedef struct fd_set {
+  unsigned int fd_count;               /* how many are SET? */
+  int fd_array[10];   /* an array of SOCKETs */
+} fd_set;

+ 3 - 0
dtool/src/parser-inc/winsock2.h

@@ -6,6 +6,9 @@
 
 
 typedef unsigned long SOCKET;
 typedef unsigned long SOCKET;
 
 
+struct sockaddr;
 struct sockaddr_in;
 struct sockaddr_in;
+struct sockaddr_in6;
+struct sockaddr_storage;
 
 
 #endif
 #endif

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

@@ -0,0 +1 @@
+typedef DWORD socklen_t;

+ 7 - 2
dtool/src/prc/notifyCategory.cxx

@@ -74,10 +74,15 @@ out(NotifySeverity severity, bool prefix) const {
       if (get_notify_timestamp()) {
       if (get_notify_timestamp()) {
         // Format a timestamp to include as a prefix as well.
         // Format a timestamp to include as a prefix as well.
         time_t now = time(NULL) + _server_delta;
         time_t now = time(NULL) + _server_delta;
-        struct tm *ptm = localtime(&now);
+        struct tm atm;
+#ifdef _WIN32
+        localtime_s(&atm, &now);
+#else
+        localtime_r(&now, &atm);
+#endif
 
 
         char buffer[128];
         char buffer[128];
-        strftime(buffer, 128, ":%m-%d-%Y %H:%M:%S ", ptm);
+        strftime(buffer, 128, ":%m-%d-%Y %H:%M:%S ", &atm);
         nout << buffer;
         nout << buffer;
       }
       }
 
 

+ 12 - 8
makepanda/makepanda.py

@@ -46,7 +46,7 @@ CFLAGS=""
 CXXFLAGS=""
 CXXFLAGS=""
 LDFLAGS=""
 LDFLAGS=""
 RTDIST=0
 RTDIST=0
-RTDIST_VERSION="dev"
+RTDIST_VERSION=None
 RUNTIME=0
 RUNTIME=0
 DISTRIBUTOR=""
 DISTRIBUTOR=""
 VERSION=None
 VERSION=None
@@ -163,13 +163,13 @@ def usage(problem):
 def parseopts(args):
 def parseopts(args):
     global INSTALLER,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION
     global INSTALLER,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
+    global DEBVERSION,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","rtdist","nocolor",
         "version=","lzma","no-python","threads=","outputdir=","override=",
         "version=","lzma","no-python","threads=","outputdir=","override=",
-        "static","host=","debversion=","rpmrelease=","p3dsuffix=",
+        "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="]
     anything = 0
     anything = 0
@@ -214,6 +214,7 @@ def parseopts(args):
             elif (option=="--rpmrelease"): RPMRELEASE=value
             elif (option=="--rpmrelease"): RPMRELEASE=value
             elif (option=="--git-commit"): GIT_COMMIT=value
             elif (option=="--git-commit"): GIT_COMMIT=value
             elif (option=="--p3dsuffix"): P3DSUFFIX=value
             elif (option=="--p3dsuffix"): P3DSUFFIX=value
+            elif (option=="--rtdist-version"): RTDIST_VERSION=value
             # Backward compatibility, OPENGL was renamed to GL
             # Backward compatibility, OPENGL was renamed to GL
             elif (option=="--use-opengl"): PkgEnable("GL")
             elif (option=="--use-opengl"): PkgEnable("GL")
             elif (option=="--no-opengl"): PkgDisable("GL")
             elif (option=="--no-opengl"): PkgDisable("GL")
@@ -400,9 +401,12 @@ if (RUNTIME or RTDIST):
 
 
 if DISTRIBUTOR == "":
 if DISTRIBUTOR == "":
     DISTRIBUTOR = "makepanda"
     DISTRIBUTOR = "makepanda"
-else:
+elif not RTDIST_VERSION:
     RTDIST_VERSION = DISTRIBUTOR.strip() + "_" + MAJOR_VERSION
     RTDIST_VERSION = DISTRIBUTOR.strip() + "_" + MAJOR_VERSION
 
 
+if not RTDIST_VERSION:
+    RTDIST_VERSION = "dev"
+
 if not IsCustomOutputDir():
 if not IsCustomOutputDir():
     if GetTarget() == "windows" and GetTargetArch() == 'x64':
     if GetTarget() == "windows" and GetTargetArch() == 'x64':
         outputdir_suffix += '_x64'
         outputdir_suffix += '_x64'
@@ -787,9 +791,9 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         SmartPkgEnable("ASSIMP",    "assimp", ("assimp"), "assimp")
         SmartPkgEnable("ASSIMP",    "assimp", ("assimp"), "assimp")
-        SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ffmpeg_libs)
-        SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale", "libswscale/swscale.h"), target_pkg = "FFMPEG")
-        SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample", "libswresample/swresample.h"), target_pkg = "FFMPEG")
+        SmartPkgEnable("FFMPEG",    ffmpeg_libs, ffmpeg_libs, ("libavformat/avformat.h", "libavcodec/avcodec.h", "libavutil/avutil.h"))
+        SmartPkgEnable("SWSCALE",   "libswscale", "libswscale", ("libswscale/swscale.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
+        SmartPkgEnable("SWRESAMPLE","libswresample", "libswresample", ("libswresample/swresample.h"), target_pkg = "FFMPEG", thirdparty_dir = "ffmpeg")
         SmartPkgEnable("FFTW",      "",          ("rfftw", "fftw"), ("fftw.h", "rfftw.h"))
         SmartPkgEnable("FFTW",      "",          ("rfftw", "fftw"), ("fftw.h", "rfftw.h"))
         SmartPkgEnable("FMODEX",    "",          ("fmodex"), ("fmodex", "fmodex/fmod.h"))
         SmartPkgEnable("FMODEX",    "",          ("fmodex"), ("fmodex", "fmodex/fmod.h"))
         SmartPkgEnable("FREETYPE",  "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h"))
         SmartPkgEnable("FREETYPE",  "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h"))
@@ -1058,7 +1062,7 @@ def CompileCxx(obj,src,opts):
             cmd = "cl "
             cmd = "cl "
             if GetTargetArch() == 'x64':
             if GetTargetArch() == 'x64':
                 cmd += "/favor:blend "
                 cmd += "/favor:blend "
-            cmd += "/wd4996 /wd4275 /wd4267 /wd4101 /wd4273 "
+            cmd += "/wd4996 /wd4275 /wd4273 "
 
 
             # Enable Windows 7 interfaces if we need Touchinput.
             # Enable Windows 7 interfaces if we need Touchinput.
             if PkgSkip("TOUCHINPUT") == 0:
             if PkgSkip("TOUCHINPUT") == 0:

+ 21 - 14
makepanda/makepandacore.py

@@ -16,10 +16,10 @@ else:
     import cPickle as pickle
     import cPickle as pickle
     import thread
     import thread
 
 
-SUFFIX_INC = [".cxx",".c",".h",".I",".yxx",".lxx",".mm",".rc",".r"]
+SUFFIX_INC = [".cxx",".cpp",".c",".h",".I",".yxx",".lxx",".mm",".rc",".r"]
 SUFFIX_DLL = [".dll",".dlo",".dle",".dli",".dlm",".mll",".exe",".pyd",".ocx"]
 SUFFIX_DLL = [".dll",".dlo",".dle",".dli",".dlm",".mll",".exe",".pyd",".ocx"]
 SUFFIX_LIB = [".lib",".ilb"]
 SUFFIX_LIB = [".lib",".ilb"]
-VCS_DIRS = set(["CVS", "CVSROOT", ".git", ".hg"])
+VCS_DIRS = set(["CVS", "CVSROOT", ".git", ".hg", "__pycache__"])
 VCS_FILES = set([".cvsignore", ".gitignore", ".gitmodules", ".hgignore"])
 VCS_FILES = set([".cvsignore", ".gitignore", ".gitmodules", ".hgignore"])
 STARTTIME = time.time()
 STARTTIME = time.time()
 MAINTHREAD = threading.currentThread()
 MAINTHREAD = threading.currentThread()
@@ -76,6 +76,7 @@ MAYAVERSIONINFO = [("MAYA6",   "6.0"),
                    ("MAYA2014","2014"),
                    ("MAYA2014","2014"),
                    ("MAYA2015","2015"),
                    ("MAYA2015","2015"),
                    ("MAYA2016","2016"),
                    ("MAYA2016","2016"),
+                   ("MAYA20165","2016.5")
 ]
 ]
 
 
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),
 MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"),
@@ -1392,7 +1393,12 @@ def PkgConfigGetDefSymbols(pkgname, tool = "pkg-config"):
     for l in result.split(" "):
     for l in result.split(" "):
         if (l.startswith("-D")):
         if (l.startswith("-D")):
             d = l.replace("-D", "").replace("\"", "").strip().split("=")
             d = l.replace("-D", "").replace("\"", "").strip().split("=")
-            if (len(d) == 1):
+
+            if d[0] in ('NDEBUG', '_DEBUG'):
+                # Setting one of these flags by accident could cause serious harm.
+                if GetVerbose():
+                    print("Ignoring %s flag provided by %s" % (l, tool))
+            elif len(d) == 1:
                 defs[d[0]] = ""
                 defs[d[0]] = ""
             else:
             else:
                 defs[d[0]] = d[1]
                 defs[d[0]] = d[1]
@@ -1452,7 +1458,7 @@ def ChooseLib(libs, thirdparty=None):
             print(ColorText("cyan", "Couldn't find any of the libraries " + ", ".join(libs)))
             print(ColorText("cyan", "Couldn't find any of the libraries " + ", ".join(libs)))
         return libs[0]
         return libs[0]
 
 
-def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None, framework = None, target_pkg = None, tool = "pkg-config"):
+def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None, framework = None, target_pkg = None, tool = "pkg-config", thirdparty_dir = None):
     global PKG_LIST_ALL
     global PKG_LIST_ALL
     if (pkg in PkgListGet() and PkgSkip(pkg)):
     if (pkg in PkgListGet() and PkgSkip(pkg)):
         return
         return
@@ -1482,16 +1488,12 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
 
 
     custom_loc = PkgHasCustomLocation(pkg)
     custom_loc = PkgHasCustomLocation(pkg)
 
 
-    if pkg.lower() == "swscale" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswscale/swscale.h"):
-        # Let it be handled by the ffmpeg package
-        LibName(target_pkg, "-lswscale")
-        return
-    if pkg.lower() == "swresample" and os.path.isfile(GetThirdpartyDir() + "ffmpeg/include/libswresample/swresample.h"):
-        LibName(target_pkg, "-lswresample")
-        return
+    # Determine the location of the thirdparty directory.
+    if not thirdparty_dir:
+        thirdparty_dir = pkg.lower()
+    pkg_dir = os.path.join(GetThirdpartyDir(), thirdparty_dir)
 
 
-    # First check if the package is in the thirdparty directory.
-    pkg_dir = os.path.join(GetThirdpartyDir(), pkg.lower())
+    # First check if the library can be found in the thirdparty directory.
     if not custom_loc and os.path.isdir(pkg_dir):
     if not custom_loc and os.path.isdir(pkg_dir):
         if framework and os.path.isdir(os.path.join(pkg_dir, framework + ".framework")):
         if framework and os.path.isdir(os.path.join(pkg_dir, framework + ".framework")):
             FrameworkDirectory(target_pkg, pkg_dir)
             FrameworkDirectory(target_pkg, pkg_dir)
@@ -1541,12 +1543,17 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
 
 
             location = LocateLibrary(libname, lpath, prefer_static=True)
             location = LocateLibrary(libname, lpath, prefer_static=True)
             if location is not None:
             if location is not None:
+                # If it's a .so or .dylib we may have changed it and copied it to the built/lib dir.
+                if location.endswith('.so') or location.endswith('.dylib'):
+                    location = os.path.join(GetOutputDir(), "lib", os.path.basename(location))
                 LibName(target_pkg, location)
                 LibName(target_pkg, location)
             else:
             else:
                 # This is for backward compatibility - in the thirdparty dir,
                 # This is for backward compatibility - in the thirdparty dir,
                 # we kept some libs with "panda" prefix, like libpandatiff.
                 # we kept some libs with "panda" prefix, like libpandatiff.
                 location = LocateLibrary("panda" + libname, lpath, prefer_static=True)
                 location = LocateLibrary("panda" + libname, lpath, prefer_static=True)
                 if location is not None:
                 if location is not None:
+                    if location.endswith('.so') or location.endswith('.dylib'):
+                        location = os.path.join(GetOutputDir(), "lib", os.path.basename(location))
                     LibName(target_pkg, location)
                     LibName(target_pkg, location)
                 else:
                 else:
                     print(GetColor("cyan") + "Couldn't find library lib" + libname + " in thirdparty directory " + pkg.lower() + GetColor())
                     print(GetColor("cyan") + "Couldn't find library lib" + libname + " in thirdparty directory " + pkg.lower() + GetColor())
@@ -2325,7 +2332,7 @@ def SetupVisualStudioEnviron():
 
 
     binpath = SDK["VISUALSTUDIO"] + "VC\\bin\\" + bindir
     binpath = SDK["VISUALSTUDIO"] + "VC\\bin\\" + bindir
     if not os.path.isdir(binpath):
     if not os.path.isdir(binpath):
-        exit("Couldn't find compilers in %s.  You may need to install the Windows SDK 7.1 and the Visual C++ 2010 SP1 Compiler Update for Windows SDK 7.1.")
+        exit("Couldn't find compilers in %s.  You may need to install the Windows SDK 7.1 and the Visual C++ 2010 SP1 Compiler Update for Windows SDK 7.1." % binpath)
 
 
     AddToPathEnv("PATH",    binpath)
     AddToPathEnv("PATH",    binpath)
     AddToPathEnv("PATH",    SDK["VISUALSTUDIO"] + "Common7\\IDE")
     AddToPathEnv("PATH",    SDK["VISUALSTUDIO"] + "Common7\\IDE")

+ 2 - 2
panda/src/audio/audioManager.cxx

@@ -40,7 +40,7 @@ Create_AudioManager_proc *AudioManager::_create_AudioManager = NULL;
 
 
 void AudioManager::
 void AudioManager::
 register_AudioManager_creator(Create_AudioManager_proc* proc) {
 register_AudioManager_creator(Create_AudioManager_proc* proc) {
-  nassertv(_create_AudioManager == NULL);
+  nassertv(_create_AudioManager == NULL || _create_AudioManager == proc);
   _create_AudioManager = proc;
   _create_AudioManager = proc;
 }
 }
 
 
@@ -71,7 +71,7 @@ PT(AudioManager) AudioManager::create_AudioManager() {
       if (handle == (void *)NULL) {
       if (handle == (void *)NULL) {
         audio_error("  load_dso(" << dl_name << ") failed, will use NullAudioManager");
         audio_error("  load_dso(" << dl_name << ") failed, will use NullAudioManager");
         audio_error("    "<<load_dso_error());
         audio_error("    "<<load_dso_error());
-        nassertr(_create_AudioManager == create_NullAudioManager, NULL);
+        nassertr(_create_AudioManager == NULL, NULL);
       } else {
       } else {
         // Get the special function from the dso, which should return the
         // Get the special function from the dso, which should return the
         // AudioManager factory function.
         // AudioManager factory function.

+ 20 - 0
panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm

@@ -97,6 +97,26 @@ get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_for
   }
   }
   // TODO: add aux buffers
   // TODO: add aux buffers
 
 
+  // Cocoa doesn't provide individual RGB bits.  Make assumptions.
+  // Note that color_size seems to be returning values like 32, which
+  // suggests that it contains the alpha size as well.
+
+  if (color_size == 24 || color_size == 32) {
+    properties.set_rgba_bits(8, 8, 8, alpha_size);
+
+  } else if (color_size == 64) {
+    properties.set_rgba_bits(16, 16, 16, alpha_size);
+
+  } else if (color_size == 128) {
+    properties.set_rgba_bits(32, 32, 32, alpha_size);
+
+  } else if (color_size >= 3) {
+    // Assume it's giving us at least one of each.
+    properties.set_red_bits(1);
+    properties.set_green_bits(1);
+    properties.set_blue_bits(1);
+  }
+
   // Extract the renderer ID bits and check if our renderer matches the known
   // Extract the renderer ID bits and check if our renderer matches the known
   // software renderers.
   // software renderers.
   renderer_id &= kCGLRendererIDMatchingMask;
   renderer_id &= kCGLRendererIDMatchingMask;

+ 20 - 0
panda/src/cocoadisplay/cocoaPandaApp.mm

@@ -25,4 +25,24 @@
     [super sendEvent: event];
     [super sendEvent: event];
   }
   }
 }
 }
+
+- (void) _setup: (void *) interp {
+  // This is called by Tk when it launches and naively assumes that it is
+  // the first to create an NSApplication.  We can't do anything about it
+  // at this point except display an error message.
+
+  cocoadisplay_cat.error()
+    << "Detected attempt to initialize Tk after creating a Panda window.  "
+       "This will likely cause a crash.\n"
+       "To fix this, set 'want-tk true' in Config.prc to force "
+       "initialization of Tk before opening the Panda window.\n";
+}
+
+- (void) _setupEventLoop {
+  NSAutoreleasePool *pool = [NSAutoreleasePool new];
+  [self finishLaunching];
+  [self setWindowsNeedUpdate:YES];
+  [pool drain];
+}
+
 @end
 @end

+ 9 - 0
panda/src/display/config_display.cxx

@@ -298,6 +298,15 @@ ConfigVariableBool allow_incomplete_render
           "geometry is always paged in immediately when needed, holding up "
           "geometry is always paged in immediately when needed, holding up "
           "the frame render if necessary."));
           "the frame render if necessary."));
 
 
+ConfigVariableBool old_alpha_blend
+("old-alpha-blend", false,
+ PRC_DESC("Set this to true to enable the old alpha blending behavior from "
+          "Panda 1.9 in which the alpha value written out to the framebuffer "
+          "is squared.  The new behavior is more intuitive when compositing "
+          "an semitransparent image produced using render-to-texture.  You "
+          "should generally leave this false unless you have an effect that "
+          "relies on the old behavior, or you suspect an implementation bug."));
+
 ConfigVariableInt win_size
 ConfigVariableInt win_size
 ("win-size", "800 600",
 ("win-size", "800 600",
  PRC_DESC("This is the default size at which to open a new window.  This "
  PRC_DESC("This is the default size at which to open a new window.  This "

+ 1 - 0
panda/src/display/config_display.h

@@ -68,6 +68,7 @@ extern EXPCL_PANDA_DISPLAY ConfigVariableBool default_stereo_camera;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool color_scale_via_lighting;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool color_scale_via_lighting;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool alpha_scale_via_texture;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool alpha_scale_via_texture;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool allow_incomplete_render;
 extern EXPCL_PANDA_DISPLAY ConfigVariableBool allow_incomplete_render;
+extern EXPCL_PANDA_DISPLAY ConfigVariableBool old_alpha_blend;
 
 
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_size;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_origin;
 extern EXPCL_PANDA_DISPLAY ConfigVariableInt win_origin;

+ 3 - 0
panda/src/display/graphicsEngine.cxx

@@ -597,6 +597,9 @@ remove_all_windows() {
   // And, hey, let's stop the vertex paging threads, if any.
   // And, hey, let's stop the vertex paging threads, if any.
   VertexDataPage::stop_threads();
   VertexDataPage::stop_threads();
 
 
+  // Stopping the tasks means we have to release the Python GIL while
+  // this method runs (hence it is marked BLOCKING), so that any
+  // Python tasks on other threads won't deadlock grabbing the GIL.
   AsyncTaskManager::get_global_ptr()->stop_threads();
   AsyncTaskManager::get_global_ptr()->stop_threads();
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS

+ 2 - 2
panda/src/display/graphicsEngine.h

@@ -53,7 +53,7 @@ class Texture;
 class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount {
 class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount {
 PUBLISHED:
 PUBLISHED:
   GraphicsEngine(Pipeline *pipeline = NULL);
   GraphicsEngine(Pipeline *pipeline = NULL);
-  ~GraphicsEngine();
+  BLOCKING ~GraphicsEngine();
 
 
   void set_threading_model(const GraphicsThreadingModel &threading_model);
   void set_threading_model(const GraphicsThreadingModel &threading_model);
   GraphicsThreadingModel get_threading_model() const;
   GraphicsThreadingModel get_threading_model() const;
@@ -94,7 +94,7 @@ PUBLISHED:
 
 
   bool add_window(GraphicsOutput *window, int sort);
   bool add_window(GraphicsOutput *window, int sort);
   bool remove_window(GraphicsOutput *window);
   bool remove_window(GraphicsOutput *window);
-  void remove_all_windows();
+  BLOCKING void remove_all_windows();
   void reset_all_windows(bool swapchain);
   void reset_all_windows(bool swapchain);
 
 
   bool is_empty() const;
   bool is_empty() const;

+ 8 - 0
panda/src/downloader/bioPtr.I

@@ -18,6 +18,14 @@ INLINE BioPtr::
 BioPtr(BIO *bio) : _bio(bio) {
 BioPtr(BIO *bio) : _bio(bio) {
 }
 }
 
 
+/**
+ *
+ */
+INLINE bool BioPtr::
+should_retry() const {
+  return (_bio != NULL) && BIO_should_retry(_bio);
+}
+
 /**
 /**
  *
  *
  */
  */

+ 167 - 5
panda/src/downloader/bioPtr.cxx

@@ -18,13 +18,46 @@
 #include "urlSpec.h"
 #include "urlSpec.h"
 #include "config_downloader.h"
 #include "config_downloader.h"
 
 
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#endif
+
+#ifdef _WIN32
+static string format_error() {
+  PVOID buffer;
+  DWORD len;
+  len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                      NULL, WSAGetLastError(), 0, (LPTSTR)&buffer, 0, NULL);
+  if (len == 0) {
+    return string("Unknown error message");
+  }
+
+  const char *text = (const char *)buffer;
+  while (len > 0 && isspace(text[len - 1])) {
+    --len;
+  }
+
+  string result(text, len);
+  LocalFree(buffer);
+  return result;
+}
+#else
+#define format_error() strerror(errno)
+#endif
+
 /**
 /**
  * This flavor of the constructor automatically creates a socket BIO and feeds
  * This flavor of the constructor automatically creates a socket BIO and feeds
  * it the server and port name from the indicated URL.  It doesn't call
  * it the server and port name from the indicated URL.  It doesn't call
  * BIO_do_connect(), though.
  * BIO_do_connect(), though.
  */
  */
 BioPtr::
 BioPtr::
-BioPtr(const URLSpec &url) {
+BioPtr(const URLSpec &url) : _connecting(false) {
   if (url.get_scheme() == "file") {
   if (url.get_scheme() == "file") {
     // We're just reading a disk file.
     // We're just reading a disk file.
     string filename = URLSpec::unquote(url.get_path());
     string filename = URLSpec::unquote(url.get_path());
@@ -48,12 +81,141 @@ BioPtr(const URLSpec &url) {
     _bio = BIO_new_file(filename.c_str(), "rb");
     _bio = BIO_new_file(filename.c_str(), "rb");
 
 
   } else {
   } else {
-    // A normal network-based URL.
+    // A normal network-based URL.  We don't use BIO_new_connect since it
+    // doesn't handle IPv6 properly.
     _server_name = url.get_server();
     _server_name = url.get_server();
     _port = url.get_port();
     _port = url.get_port();
-    _bio = BIO_new_connect((char *)_server_name.c_str());
-    BIO_set_conn_int_port(_bio, &_port);
+    _bio = NULL;
+
+    // These hints tell getaddrinfo what kind of address to return.
+    struct addrinfo hints, *res = NULL;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+    hints.ai_family = support_ipv6 ? AF_UNSPEC : AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+
+    // Resolve the hostname or address string.
+    int result = getaddrinfo(_server_name.c_str(), NULL, &hints, &res);
+    if (result != 0) {
+      const char *errmsg;
+#ifndef _WIN32
+      if (result == EAI_SYSTEM && errno != 0) {
+        errmsg = strerror(errno);
+      } else
+#endif
+      {
+        errmsg = gai_strerror(result);
+      }
+      downloader_cat.error()
+        << "Failed to resolve " << url.get_server() << ": " << errmsg << "\n";
+      return;
+    }
+    nassertv(res != NULL && res->ai_addr != NULL);
+
+    // Store the real resolved address.
+    char buf[48];
+    buf[0] = 0;
+#ifdef _WIN32
+    DWORD bufsize = sizeof(buf);
+    WSAAddressToStringA(res->ai_addr, res->ai_addrlen, NULL, buf, &bufsize);
+#else
+    if (res->ai_addr->sa_family == AF_INET) {
+      inet_ntop(AF_INET, (char *)&((sockaddr_in *)res->ai_addr)->sin_addr, buf, sizeof(buf));
+
+    } else if (res->ai_addr->sa_family == AF_INET6) {
+      inet_ntop(AF_INET6, (char *)&((sockaddr_in6 *)res->ai_addr)->sin6_addr, buf, sizeof(buf));
+    }
+#endif
+
+    if (buf[0]) {
+      _server_name = buf;
+    }
+    if (downloader_cat.is_debug()) {
+      downloader_cat.debug()
+        << "Resolved " << url.get_server() << " to " << buf << "\n";
+    }
+
+    // Create the socket.
+    int fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
+    if (fd < 0) {
+      downloader_cat.error()
+        << "Failed to create socket: " << format_error() << "\n";
+      _bio = NULL;
+      freeaddrinfo(res);
+      return;
+    }
+
+    // Store the address and length for later use in connect().
+    nassertv(res->ai_addrlen <= sizeof(_addr));
+    memcpy(&_addr, res->ai_addr, res->ai_addrlen);
+    _addrlen = res->ai_addrlen;
+    freeaddrinfo(res);
+
+    // Also set the port we'd like to connect to.
+    if (_addr.ss_family == AF_INET) {
+      ((sockaddr_in &)_addr).sin_port = htons(_port);
+    } else if (_addr.ss_family == AF_INET6) {
+      ((sockaddr_in6 &)_addr).sin6_port = htons(_port);
+    }
+
+    _bio = BIO_new_socket(fd, 1);
+  }
+}
+
+/**
+ * Sets the non-blocking flag on the socket.
+ */
+void BioPtr::
+set_nbio(bool nbio) {
+  if (_bio == NULL) {
+    return;
+  }
+
+  int fd = -1;
+  BIO_get_fd(_bio, &fd);
+  nassertv_always(fd >= 0);
+
+  BIO_socket_nbio(fd, nbio);
+}
+
+/**
+ * Connects to the socket.  Returns true on success.
+ */
+bool BioPtr::
+connect() {
+  if (_bio == NULL) {
+    return false;
+  }
+
+  int fd = -1;
+  BIO_get_fd(_bio, &fd);
+  nassertr(fd >= 0, false);
+
+  int result;
+  if (_connecting) {
+    result = BIO_sock_error(fd);
+  } else {
+    result = ::connect(fd, (sockaddr *)&_addr, _addrlen);
+
+    if (result != 0 && BIO_sock_should_retry(-1)) {
+      // It's still in progress; we should retry later.  This causes
+      // should_reply() to return true.
+      BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
+      _connecting = true;
+      return false;
+    }
   }
   }
+  BIO_clear_retry_flags(_bio);
+  _connecting = false;
+
+  if (result != 0) {
+    downloader_cat.warning()
+      << "Failed to connect to " << _server_name << " port " << _port
+      << ": " << format_error() << "\n";
+    return false;
+  }
+
+  return true;
 }
 }
 
 
 /**
 /**
@@ -64,7 +226,7 @@ BioPtr::
   if (_bio != (BIO *)NULL) {
   if (_bio != (BIO *)NULL) {
     if (downloader_cat.is_debug() && !_server_name.empty()) {
     if (downloader_cat.is_debug() && !_server_name.empty()) {
       downloader_cat.debug()
       downloader_cat.debug()
-        << "Dropping connection to " << _server_name << ":" << _port << "\n";
+        << "Dropping connection to " << _server_name << " port " << _port << "\n";
     }
     }
 
 
     BIO_free_all(_bio);
     BIO_free_all(_bio);

+ 16 - 0
panda/src/downloader/bioPtr.h

@@ -27,6 +27,14 @@
 #include "openSSLWrapper.h"  // must be included before any other openssl.
 #include "openSSLWrapper.h"  // must be included before any other openssl.
 #include "openssl/ssl.h"
 #include "openssl/ssl.h"
 
 
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
 class URLSpec;
 class URLSpec;
 
 
 /**
 /**
@@ -41,6 +49,11 @@ public:
   BioPtr(const URLSpec &url);
   BioPtr(const URLSpec &url);
   virtual ~BioPtr();
   virtual ~BioPtr();
 
 
+  void set_nbio(bool nbio);
+  bool connect();
+
+  INLINE bool should_retry() const;
+
   INLINE BIO &operator *() const;
   INLINE BIO &operator *() const;
   INLINE BIO *operator -> () const;
   INLINE BIO *operator -> () const;
   INLINE operator BIO * () const;
   INLINE operator BIO * () const;
@@ -55,6 +68,9 @@ private:
   BIO *_bio;
   BIO *_bio;
   string _server_name;
   string _server_name;
   int _port;
   int _port;
+  struct sockaddr_storage _addr;
+  socklen_t _addrlen;
+  bool _connecting;
 };
 };
 
 
 #include "bioPtr.I"
 #include "bioPtr.I"

+ 6 - 0
panda/src/downloader/config_downloader.cxx

@@ -111,6 +111,12 @@ ConfigVariableInt tcp_header_size
           "length when writing a datagram on a TCP stream.  This may be "
           "length when writing a datagram on a TCP stream.  This may be "
           "0, 2, or 4.  The server and client must agree on this value."));
           "0, 2, or 4.  The server and client must agree on this value."));
 
 
+ConfigVariableBool support_ipv6
+("support-ipv6", true,
+ PRC_DESC("Specifies whether IPv6 support should be enabled.  This should "
+          "be true unless you are experiencing issues with Panda's IPv6 "
+          "support or are using a misconfigured system."));
+
 ConfigureFn(config_downloader) {
 ConfigureFn(config_downloader) {
   init_libdownloader();
   init_libdownloader();
 }
 }

+ 1 - 0
panda/src/downloader/config_downloader.h

@@ -45,6 +45,7 @@ extern ConfigVariableDouble http_idle_timeout;
 extern ConfigVariableInt http_max_connect_count;
 extern ConfigVariableInt http_max_connect_count;
 
 
 extern EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size;
 extern EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size;
+extern EXPCL_PANDAEXPRESS ConfigVariableBool support_ipv6;
 
 
 extern EXPCL_PANDAEXPRESS void init_libdownloader();
 extern EXPCL_PANDAEXPRESS void init_libdownloader();
 
 

+ 41 - 18
panda/src/downloader/httpChannel.cxx

@@ -375,26 +375,28 @@ run() {
       }
       }
 
 
       // No connection.  Attempt to establish one.
       // No connection.  Attempt to establish one.
+      URLSpec url;
       if (_proxy.empty()) {
       if (_proxy.empty()) {
-        _bio = new BioPtr(_request.get_url());
+        url = _request.get_url();
       } else {
       } else {
-        _bio = new BioPtr(_proxy);
+        url = _proxy;
       }
       }
+      _bio = new BioPtr(url);
       _source = new BioStreamPtr(new BioStream(_bio));
       _source = new BioStreamPtr(new BioStream(_bio));
       if (_nonblocking) {
       if (_nonblocking) {
-        BIO_set_nbio(*_bio, 1);
+        _bio->set_nbio(true);
       }
       }
 
 
       if (downloader_cat.is_debug()) {
       if (downloader_cat.is_debug()) {
         if (_connect_count > 0) {
         if (_connect_count > 0) {
           downloader_cat.debug()
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Reconnecting to " << _bio->get_server_name() << ":"
+            << "Reconnecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
             << _bio->get_port() << "\n";
         } else {
         } else {
           downloader_cat.debug()
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Connecting to " << _bio->get_server_name() << ":"
+            << "Connecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
             << _bio->get_port() << "\n";
         }
         }
       }
       }
@@ -941,14 +943,14 @@ bool HTTPChannel::
 run_connecting() {
 run_connecting() {
   _status_entry = StatusEntry();
   _status_entry = StatusEntry();
 
 
-  if (BIO_do_connect(*_bio) <= 0) {
-    if (BIO_should_retry(*_bio)) {
+  if (!_bio->connect()) {
+    if (_bio->should_retry()) {
       _state = S_connecting_wait;
       _state = S_connecting_wait;
       return false;
       return false;
     }
     }
     downloader_cat.info()
     downloader_cat.info()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
-      << "Could not connect to " << _bio->get_server_name() << ":"
+      << "Could not connect to " << _bio->get_server_name() << " port "
       << _bio->get_port() << "\n";
       << _bio->get_port() << "\n";
     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
     _status_entry._status_code = SC_no_connection;
     _status_entry._status_code = SC_no_connection;
@@ -959,7 +961,7 @@ run_connecting() {
   if (downloader_cat.is_debug()) {
   if (downloader_cat.is_debug()) {
     downloader_cat.debug()
     downloader_cat.debug()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
-      << "Connected to " << _bio->get_server_name() << ":"
+      << "Connected to " << _bio->get_server_name() << " port "
       << _bio->get_port() << "\n";
       << _bio->get_port() << "\n";
   }
   }
 
 
@@ -1362,6 +1364,10 @@ run_socks_proxy_connect_reply() {
     total_bytes += (unsigned int)reply[4];
     total_bytes += (unsigned int)reply[4];
     break;
     break;
 
 
+  case 0x04:  // IPv6
+    total_bytes += 16;
+    break;
+
   default:
   default:
     downloader_cat.info()
     downloader_cat.info()
       << _NOTIFY_HTTP_CHANNEL_ID
       << _NOTIFY_HTTP_CHANNEL_ID
@@ -1396,6 +1402,18 @@ run_socks_proxy_connect_reply() {
     case 0x03:  // DNS
     case 0x03:  // DNS
       connect_host = string(&reply[5], (unsigned int)reply[4]);
       connect_host = string(&reply[5], (unsigned int)reply[4]);
       break;
       break;
+
+    case 0x04:  // IPv6
+      {
+        char buf[48];
+        sprintf(buf, "[%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx"
+                     ":%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx]",
+                reply[4], reply[5], reply[6], reply[7], reply[8], reply[9],
+                reply[10], reply[11], reply[12], reply[13], reply[14],
+                reply[15], reply[16], reply[17], reply[18], reply[19]);
+        total_bytes += 16;
+      }
+      break;
     }
     }
 
 
     int connect_port =
     int connect_port =
@@ -2742,8 +2760,8 @@ server_getline(string &str) {
         }
         }
         str = str.substr(0, p);
         str = str.substr(0, p);
       }
       }
-      if (downloader_cat.is_debug()) {
-        downloader_cat.debug()
+      if (downloader_cat.is_spam()) {
+        downloader_cat.spam()
           << _NOTIFY_HTTP_CHANNEL_ID
           << _NOTIFY_HTTP_CHANNEL_ID
           << "recv: " << str << "\n";
           << "recv: " << str << "\n";
       }
       }
@@ -2915,7 +2933,7 @@ server_send(const string &str, bool secret) {
   }
   }
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
-  if (!secret && downloader_cat.is_debug()) {
+  if (!secret && downloader_cat.is_spam()) {
     show_send(str.substr(0, write_count));
     show_send(str.substr(0, write_count));
   }
   }
 #endif
 #endif
@@ -3486,14 +3504,19 @@ make_header() {
 
 
   if (_client->get_http_version() >= HTTPEnum::HV_11) {
   if (_client->get_http_version() >= HTTPEnum::HV_11) {
 
 
-    stream
-      << "Host: " << _request.get_url().get_server();
-    if (!_request.get_url().is_default_port()) {
+    if (_request.get_url().has_port() && _request.get_url().is_default_port()) {
       // It appears that some servers (notably gstatic.com) might return a 404
       // It appears that some servers (notably gstatic.com) might return a 404
       // if you include an explicit port number in with the Host: header, even
       // if you include an explicit port number in with the Host: header, even
       // if it is the default port.  So, don't include the port number unless
       // if it is the default port.  So, don't include the port number unless
       // we need to.
       // we need to.
-      stream << ":" << _request.get_url().get_port();
+      string server = _request.get_url().get_server();
+      if (server.find(':') != string::npos) {
+        stream << "Host: [" << server << "]";
+      } else {
+        stream << "Host: " << server;
+      }
+    } else {
+      stream << "Host: " << _request.get_url().get_server_and_port();
     }
     }
     stream << "\r\n";
     stream << "\r\n";
     if (!get_persistent_connection()) {
     if (!get_persistent_connection()) {
@@ -3703,14 +3726,14 @@ show_send(const string &message) {
   size_t newline = message.find('\n', start);
   size_t newline = message.find('\n', start);
   while (newline != string::npos) {
   while (newline != string::npos) {
     // Assume every \n is preceded by a \r.
     // Assume every \n is preceded by a \r.
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "send: " << message.substr(start, newline - start - 1) << "\n";
       << "send: " << message.substr(start, newline - start - 1) << "\n";
     start = newline + 1;
     start = newline + 1;
     newline = message.find('\n', start);
     newline = message.find('\n', start);
   }
   }
 
 
   if (start < message.length()) {
   if (start < message.length()) {
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "send: " << message.substr(start) << " (no newline)\n";
       << "send: " << message.substr(start) << " (no newline)\n";
   }
   }
 }
 }

+ 3 - 2
panda/src/downloader/httpDate.cxx

@@ -223,8 +223,9 @@ HTTPDate(const string &format) {
     struct tm *tp = localtime(&now);
     struct tm *tp = localtime(&now);
     _time -= tp->tm_gmtoff;
     _time -= tp->tm_gmtoff;
 #elif defined(_WIN32)
 #elif defined(_WIN32)
-    extern long int _timezone;
-    _time -= _timezone;
+    long int timezone;
+    _get_timezone(&timezone);
+    _time -= timezone;
 #else
 #else
     extern long int timezone;
     extern long int timezone;
     _time -= timezone;
     _time -= timezone;

+ 5 - 13
panda/src/downloader/multiplexStreamBuf.cxx

@@ -12,6 +12,7 @@
  */
  */
 
 
 #include "multiplexStreamBuf.h"
 #include "multiplexStreamBuf.h"
+#include "lightMutexHolder.h"
 
 
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #define WINDOWS_LEAN_AND_MEAN
 #define WINDOWS_LEAN_AND_MEAN
@@ -113,10 +114,8 @@ void MultiplexStreamBuf::
 add_output(MultiplexStreamBuf::BufferType buffer_type,
 add_output(MultiplexStreamBuf::BufferType buffer_type,
            MultiplexStreamBuf::OutputType output_type,
            MultiplexStreamBuf::OutputType output_type,
            ostream *out, FILE *fout, bool owns_obj) {
            ostream *out, FILE *fout, bool owns_obj) {
-#ifdef OLD_HAVE_IPC
   // Ensure that we have the mutex while we fiddle with the list of outputs.
   // Ensure that we have the mutex while we fiddle with the list of outputs.
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
 
   Output o;
   Output o;
   o._buffer_type = buffer_type;
   o._buffer_type = buffer_type;
@@ -133,9 +132,7 @@ add_output(MultiplexStreamBuf::BufferType buffer_type,
  */
  */
 void MultiplexStreamBuf::
 void MultiplexStreamBuf::
 flush() {
 flush() {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
 
   write_chars("", 0, true);
   write_chars("", 0, true);
 }
 }
@@ -146,9 +143,7 @@ flush() {
  */
  */
 int MultiplexStreamBuf::
 int MultiplexStreamBuf::
 overflow(int ch) {
 overflow(int ch) {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
 
   streamsize n = pptr() - pbase();
   streamsize n = pptr() - pbase();
 
 
@@ -172,9 +167,7 @@ overflow(int ch) {
  */
  */
 int MultiplexStreamBuf::
 int MultiplexStreamBuf::
 sync() {
 sync() {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
 
   streamsize n = pptr() - pbase();
   streamsize n = pptr() - pbase();
 
 
@@ -242,5 +235,4 @@ write_chars(const char *start, int length, bool flush) {
       break;
       break;
     }
     }
   }
   }
-
 }
 }

+ 2 - 0
panda/src/downloader/multiplexStreamBuf.h

@@ -17,6 +17,7 @@
 #include "pandabase.h"
 #include "pandabase.h"
 
 
 #include "pvector.h"
 #include "pvector.h"
+#include "lightMutex.h"
 #include <stdio.h>
 #include <stdio.h>
 
 
 /**
 /**
@@ -69,6 +70,7 @@ private:
   typedef pvector<Output> Outputs;
   typedef pvector<Output> Outputs;
   Outputs _outputs;
   Outputs _outputs;
 
 
+  LightMutex _lock;
   string _line_buffer;
   string _line_buffer;
 };
 };
 
 

+ 26 - 24
panda/src/downloader/urlSpec.I

@@ -19,14 +19,6 @@ URLSpec(const string &url, bool server_name_expected) {
   set_url(url, server_name_expected);
   set_url(url, server_name_expected);
 }
 }
 
 
-/**
- *
- */
-INLINE URLSpec::
-URLSpec(const URLSpec &copy) {
-  (*this) = copy;
-}
-
 /**
 /**
  *
  *
  */
  */
@@ -40,7 +32,7 @@ operator = (const string &url) {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator == (const URLSpec &other) const {
 operator == (const URLSpec &other) const {
-  return _url == other._url;
+  return compare_to(other) == 0;
 }
 }
 
 
 /**
 /**
@@ -48,7 +40,7 @@ operator == (const URLSpec &other) const {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator != (const URLSpec &other) const {
 operator != (const URLSpec &other) const {
-  return !operator == (other);
+  return compare_to(other) != 0;
 }
 }
 
 
 /**
 /**
@@ -56,16 +48,7 @@ operator != (const URLSpec &other) const {
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 operator < (const URLSpec &other) const {
 operator < (const URLSpec &other) const {
-  return _url < other._url;
-}
-
-/**
- * Returns a number less than zero if this URLSpec sorts before the other one,
- * greater than zero if it sorts after, or zero if they are equivalent.
- */
-INLINE int URLSpec::
-compare_to(const URLSpec &other) const {
-  return strcmp(_url.c_str(), other._url.c_str());
+  return compare_to(other) < 0;
 }
 }
 
 
 /**
 /**
@@ -148,7 +131,8 @@ get_username() const {
 }
 }
 
 
 /**
 /**
- * Returns the server name specified by the URL, if any.
+ * Returns the server name specified by the URL, if any.  In case of an IPv6
+ * address, does not include the enclosing brackets.
  */
  */
 INLINE string URLSpec::
 INLINE string URLSpec::
 get_server() const {
 get_server() const {
@@ -218,13 +202,23 @@ c_str() const {
 }
 }
 
 
 /**
 /**
- *
+ * Returns false if the URLSpec is valid (not empty), or true if it is an
+ * empty string.
  */
  */
 INLINE bool URLSpec::
 INLINE bool URLSpec::
 empty() const {
 empty() const {
   return _url.empty();
   return _url.empty();
 }
 }
 
 
+/**
+ * Returns true if the URLSpec is valid (not empty), or false if it is an
+ * empty string.
+ */
+INLINE URLSpec::
+operator bool() const {
+  return !_url.empty();
+}
+
 /**
 /**
  *
  *
  */
  */
@@ -233,12 +227,20 @@ length() const {
   return _url.length();
   return _url.length();
 }
 }
 
 
+/**
+ *
+ */
+INLINE size_t URLSpec::
+size() const {
+  return _url.size();
+}
+
 /**
 /**
  *
  *
  */
  */
 INLINE char URLSpec::
 INLINE char URLSpec::
-operator [] (int n) const {
-  nassertr(n >= 0 && n < (int)_url.length(), '\0');
+operator [] (size_t n) const {
+  nassertr(n < _url.length(), '\0');
   return _url[n];
   return _url[n];
 }
 }
 
 

+ 166 - 34
panda/src/downloader/urlSpec.cxx

@@ -12,10 +12,11 @@
  */
  */
 
 
 #include "urlSpec.h"
 #include "urlSpec.h"
+#include "filename.h"
+#include "string_utils.h"
 
 
 #include <ctype.h>
 #include <ctype.h>
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -35,24 +36,88 @@ URLSpec() {
   _query_start = 0;
   _query_start = 0;
 }
 }
 
 
+/**
+ * Creates a URLSpec by appending a path to the end of the old URLSpec,
+ * inserting an intervening forward slash if necessary.
+ */
+URLSpec::
+URLSpec(const URLSpec &url, const Filename &path) {
+  (*this) = url;
+  if (!path.empty()) {
+    string dirname = get_path();
+
+    // Check if the path already ends in a slash.
+    if (!dirname.empty() && dirname[dirname.size() - 1] == '/') {
+      if (path[0] == '/') {
+        // And the filename begins with one.  Remove the extra slash.
+        dirname.resize(dirname.size() - 1);
+      }
+    } else {
+      if (path[0] != '/') {
+        // Neither has a slash, so insert one.
+        dirname += '/';
+      }
+    }
+    set_path(dirname + path.get_fullpath());
+  }
+}
+
+/**
+ * Returns a number less than zero if this URLSpec sorts before the other one,
+ * greater than zero if it sorts after, or zero if they are equivalent.
+ */
+int URLSpec::
+compare_to(const URLSpec &other) const {
+  int cmp;
+  if (has_scheme() != other.has_scheme()) {
+    return (has_scheme() < other.has_scheme()) ? -1 : 1;
+  }
+  if (has_scheme()) {
+    cmp = cmp_nocase(get_scheme(), other.get_scheme());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  if (has_username() != other.has_username()) {
+    return (has_username() < other.has_username()) ? -1 : 1;
+  }
+  if (has_username()) {
+    cmp = get_username().compare(other.get_username());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  if (has_server() != other.has_server()) {
+    return (has_server() < other.has_server()) ? -1 : 1;
+  }
+  if (has_server()) {
+    cmp = cmp_nocase(get_server(), other.get_server());
+    if (cmp != 0) {
+      return cmp;
+    }
+  }
+  return get_path_and_query().compare(other.get_path_and_query());
+}
+
 /**
 /**
  *
  *
  */
  */
-void URLSpec::
-operator = (const URLSpec &copy) {
-  _url = copy._url;
-  _port = copy._port;
-  _flags = copy._flags;
-  _scheme_end = copy._scheme_end;
-  _username_start = copy._username_start;
-  _username_end = copy._username_end;
-  _server_start = copy._server_start;
-  _server_end = copy._server_end;
-  _port_start = copy._port_start;
-  _port_end = copy._port_end;
-  _path_start = copy._path_start;
-  _path_end = copy._path_end;
-  _query_start = copy._query_start;
+size_t URLSpec::
+get_hash() const {
+  size_t hash = 0;
+  hash = int_hash::add_hash(hash, _flags & (F_has_scheme | F_has_username | F_has_server));
+  if (has_scheme()) {
+    hash = string_hash::add_hash(hash, downcase(get_scheme()));
+  }
+  if (has_username()) {
+    hash = string_hash::add_hash(hash, get_username());
+  }
+  if (has_server()) {
+    hash = string_hash::add_hash(hash, downcase(get_server()));
+  }
+  hash = int_hash::add_hash(hash, get_port());
+  hash = string_hash::add_hash(hash, get_path_and_query());
+  return hash;
 }
 }
 
 
 /**
 /**
@@ -71,7 +136,7 @@ get_scheme() const {
  * Returns the port number specified by the URL, or the default port if not
  * Returns the port number specified by the URL, or the default port if not
  * specified.
  * specified.
  */
  */
-int URLSpec::
+uint16_t URLSpec::
 get_port() const {
 get_port() const {
   if (has_port()) {
   if (has_port()) {
     return _port;
     return _port;
@@ -115,14 +180,25 @@ get_default_port_for_scheme(const string &scheme) {
  * Returns a string consisting of the server name, followed by a colon,
  * Returns a string consisting of the server name, followed by a colon,
  * followed by the port number.  If the port number is not explicitly given in
  * followed by the port number.  If the port number is not explicitly given in
  * the URL, this string will include the implicit port number.
  * the URL, this string will include the implicit port number.
+ * If the server is an IPv6 address, it will be enclosed in square brackets.
  */
  */
 string URLSpec::
 string URLSpec::
 get_server_and_port() const {
 get_server_and_port() const {
+  ostringstream strm;
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    strm << '[' << server << ']';
+
+  } else {
+    if (!has_port()) {
+      return server;
+    }
+    strm << server;
+  }
   if (has_port()) {
   if (has_port()) {
-    return _url.substr(_server_start, _port_end - _server_start);
+    strm << ":" << get_port();
   }
   }
-  ostringstream strm;
-  strm << get_server() << ":" << get_port();
   return strm.str();
   return strm.str();
 }
 }
 
 
@@ -285,7 +361,15 @@ set_username(const string &username) {
   if (!username.empty()) {
   if (!username.empty()) {
     authority = username + "@";
     authority = username + "@";
   }
   }
-  authority += get_server();
+
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
+
   if (has_port()) {
   if (has_port()) {
     authority += ":";
     authority += ":";
     authority += get_port_str();
     authority += get_port_str();
@@ -296,6 +380,8 @@ set_username(const string &username) {
 
 
 /**
 /**
  * Replaces the server part of the URL specification.
  * Replaces the server part of the URL specification.
+ * Unlike set_server_and_port, this method does not require IPv6 addresses to
+ * be enclosed in square brackets.
  */
  */
 void URLSpec::
 void URLSpec::
 set_server(const string &server) {
 set_server(const string &server) {
@@ -307,7 +393,14 @@ set_server(const string &server) {
   if (has_username()) {
   if (has_username()) {
     authority = get_username() + "@";
     authority = get_username() + "@";
   }
   }
-  authority += server;
+
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
+
   if (has_port()) {
   if (has_port()) {
     authority += ":";
     authority += ":";
     authority += get_port_str();
     authority += get_port_str();
@@ -329,7 +422,14 @@ set_port(const string &port) {
   if (has_username()) {
   if (has_username()) {
     authority = get_username() + "@";
     authority = get_username() + "@";
   }
   }
-  authority += get_server();
+
+  string server = get_server();
+  if (server.find(':') != string::npos) {
+    // Protect an IPv6 address by enclosing it in square brackets.
+    authority += "[" + server + "]";
+  } else {
+    authority += server;
+  }
 
 
   if (!port.empty()) {
   if (!port.empty()) {
     authority += ":";
     authority += ":";
@@ -344,16 +444,15 @@ set_port(const string &port) {
  * number.
  * number.
  */
  */
 void URLSpec::
 void URLSpec::
-set_port(int port) {
-  ostringstream str;
-  str << port;
-  set_port(str.str());
+set_port(uint16_t port) {
+  set_port(format_string(port));
 }
 }
 
 
 /**
 /**
  * Replaces the server and port parts of the URL specification simultaneously.
  * Replaces the server and port parts of the URL specification simultaneously.
  * The input string should be of the form "server:port", or just "server" to
  * The input string should be of the form "server:port", or just "server" to
  * make the port number implicit.
  * make the port number implicit.
+ * Any IPv6 address must be enclosed in square brackets.
  */
  */
 void URLSpec::
 void URLSpec::
 set_server_and_port(const string &server_and_port) {
 set_server_and_port(const string &server_and_port) {
@@ -476,6 +575,18 @@ set_url(const string &url, bool server_name_expected) {
     }
     }
   }
   }
 
 
+  // Now normalize the percent-encoding sequences by making them uppercase.
+  for (p = 0; p + 2 < _url.length();) {
+    if (_url[p++] == '%') {
+      if (_url[p] != '%') {
+        _url[p] = toupper(_url[p]);
+        ++p;
+        _url[p] = toupper(_url[p]);
+      }
+      ++p;
+    }
+  }
+
   // What have we got?
   // What have we got?
   _flags = 0;
   _flags = 0;
   _port = 0;
   _port = 0;
@@ -781,18 +892,39 @@ parse_authority() {
     _server_start = at_sign + 1;
     _server_start = at_sign + 1;
   }
   }
 
 
-  // Is there a port?
-  size_t colon = _url.find(':', _server_start);
-  if (colon < _port_end) {
-    // Yep.
+  // Is this an IPv6 address in square brackets?
+  size_t bracket = _url.find('[', _server_start);
+  if (bracket < _port_end) {
+    // We won't include the brackets in the server name.
+    ++_server_start;
+
+    bracket = _url.find(']');
+    if (bracket < _server_end) {
+      _server_end = bracket;
+
+      // Is it followed directly by a port colon?
+      size_t colon = _url.find(':', _server_end);
+      if (colon < _port_end) {
+        _port_start = colon + 1;
+      }
+    }
+  } else {
+    // Is there a port?
+    size_t colon = _url.find(':', _server_start);
+    if (colon < _port_end) {
+      // Yep.
+      _server_end = colon;
+      _port_start = colon + 1;
+    }
+  }
+
+  if (_port_start < _port_end) {
     _flags |= F_has_port;
     _flags |= F_has_port;
-    _server_end = colon;
-    _port_start = colon + 1;
 
 
     // Decode the port into an integer.  Don't bother to error check if it's
     // Decode the port into an integer.  Don't bother to error check if it's
     // not really an integer.
     // not really an integer.
     string port_str = _url.substr(_port_start, _port_end - _port_start);
     string port_str = _url.substr(_port_start, _port_end - _port_start);
-    _port = atoi(port_str.c_str());
+    _port = (uint16_t)atoi(port_str.c_str());
   }
   }
 
 
   // Make sure the server name is lowercase only.
   // Make sure the server name is lowercase only.

+ 21 - 7
panda/src/downloader/urlSpec.h

@@ -17,6 +17,8 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "pnotify.h"
 #include "pnotify.h"
 
 
+class Filename;
+
 /**
 /**
  * A container for a URL, e.g.  "http://server:port/path".
  * A container for a URL, e.g.  "http://server:port/path".
  *
  *
@@ -27,14 +29,14 @@ class EXPCL_PANDAEXPRESS URLSpec {
 PUBLISHED:
 PUBLISHED:
   URLSpec();
   URLSpec();
   INLINE URLSpec(const string &url, bool server_name_expected = false);
   INLINE URLSpec(const string &url, bool server_name_expected = false);
-  INLINE URLSpec(const URLSpec &copy);
+  URLSpec(const URLSpec &url, const Filename &path);
   INLINE void operator = (const string &url);
   INLINE void operator = (const string &url);
-  void operator = (const URLSpec &copy);
 
 
   INLINE bool operator == (const URLSpec &other) const;
   INLINE bool operator == (const URLSpec &other) const;
   INLINE bool operator != (const URLSpec &other) const;
   INLINE bool operator != (const URLSpec &other) const;
   INLINE bool operator < (const URLSpec &other) const;
   INLINE bool operator < (const URLSpec &other) const;
-  INLINE int compare_to(const URLSpec &other) const;
+  int compare_to(const URLSpec &other) const;
+  size_t get_hash() const;
 
 
   INLINE bool has_scheme() const;
   INLINE bool has_scheme() const;
   INLINE bool has_authority() const;
   INLINE bool has_authority() const;
@@ -49,7 +51,7 @@ PUBLISHED:
   INLINE string get_username() const;
   INLINE string get_username() const;
   INLINE string get_server() const;
   INLINE string get_server() const;
   INLINE string get_port_str() const;
   INLINE string get_port_str() const;
-  int get_port() const;
+  uint16_t get_port() const;
   string get_server_and_port() const;
   string get_server_and_port() const;
   bool is_default_port() const;
   bool is_default_port() const;
   static int get_default_port_for_scheme(const string &scheme);
   static int get_default_port_for_scheme(const string &scheme);
@@ -65,7 +67,7 @@ PUBLISHED:
   void set_username(const string &username);
   void set_username(const string &username);
   void set_server(const string &server);
   void set_server(const string &server);
   void set_port(const string &port);
   void set_port(const string &port);
-  void set_port(int port);
+  void set_port(uint16_t port);
   void set_server_and_port(const string &server_and_port);
   void set_server_and_port(const string &server_and_port);
   void set_path(const string &path);
   void set_path(const string &path);
   void set_query(const string &query);
   void set_query(const string &query);
@@ -75,8 +77,10 @@ PUBLISHED:
   INLINE operator const string & () const;
   INLINE operator const string & () const;
   INLINE const char *c_str() const;
   INLINE const char *c_str() const;
   INLINE bool empty() const;
   INLINE bool empty() const;
+  INLINE operator bool() const;
   INLINE size_t length() const;
   INLINE size_t length() const;
-  INLINE char operator [] (int n) const;
+  INLINE size_t size() const;
+  INLINE char operator [] (size_t n) const;
 
 
   bool input(istream &in);
   bool input(istream &in);
   void output(ostream &out) const;
   void output(ostream &out) const;
@@ -86,6 +90,16 @@ PUBLISHED:
   static string unquote(const string &source);
   static string unquote(const string &source);
   static string unquote_plus(const string &source);
   static string unquote_plus(const string &source);
 
 
+  MAKE_PROPERTY(scheme, get_scheme, set_scheme);
+  MAKE_PROPERTY(authority, get_authority, set_authority);
+  MAKE_PROPERTY(username, get_username, set_username);
+  MAKE_PROPERTY(server, get_server, set_server);
+  MAKE_PROPERTY(port, get_port, set_port);
+  MAKE_PROPERTY(server_and_port, get_server_and_port, set_server_and_port);
+  MAKE_PROPERTY(path, get_path, set_path);
+  MAKE_PROPERTY(query, get_query, set_query);
+  MAKE_PROPERTY(ssl, is_ssl);
+
 private:
 private:
   void parse_authority();
   void parse_authority();
 
 
@@ -100,7 +114,7 @@ private:
   };
   };
 
 
   string _url;
   string _url;
-  int _port;
+  uint16_t _port;
   int _flags;
   int _flags;
 
 
   size_t _scheme_end;
   size_t _scheme_end;

+ 11 - 1
panda/src/downloadertools/multify.cxx

@@ -18,6 +18,7 @@
 #include "filename.h"
 #include "filename.h"
 #include "pset.h"
 #include "pset.h"
 #include "vector_string.h"
 #include "vector_string.h"
+#include "virtualFileSystem.h"
 #include <stdio.h>
 #include <stdio.h>
 #include <time.h>
 #include <time.h>
 
 
@@ -631,8 +632,17 @@ list_files(const vector_string &params) {
     cerr << multifile_name << " not found.\n";
     cerr << multifile_name << " not found.\n";
     return false;
     return false;
   }
   }
+  // We happen to know that we can read the index without doing a seek.
+  // So this is the only place where we accept a .pz/.gz compressed .mf.
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+  istream *istr = vfs->open_read_file(multifile_name, true);
+  if (istr == NULL) {
+    cerr << "Unable to open " << multifile_name << " for reading.\n";
+    return false;
+  }
+
   PT(Multifile) multifile = new Multifile;
   PT(Multifile) multifile = new Multifile;
-  if (!multifile->open_read(multifile_name)) {
+  if (!multifile->open_read(new IStreamWrapper(istr, true), true)) {
     cerr << "Unable to open " << multifile_name << " for reading.\n";
     cerr << "Unable to open " << multifile_name << " for reading.\n";
     return false;
     return false;
   }
   }

+ 8 - 1
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3798,7 +3798,14 @@ do_issue_blending() {
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_dual:
   case TransparencyAttrib::M_dual:
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
-    set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+    if (old_alpha_blend) {
+      set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+    } else {
+      set_render_state(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+      set_render_state(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD);
+      set_render_state(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
+      set_render_state(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
+    }
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

+ 8 - 0
panda/src/dxml/config_dxml.cxx

@@ -94,7 +94,15 @@ BEGIN_PUBLISH
 void
 void
 print_xml_to_file(const Filename &filename, TiXmlNode *xnode) {
 print_xml_to_file(const Filename &filename, TiXmlNode *xnode) {
   string os_name = filename.to_os_specific();
   string os_name = filename.to_os_specific();
+#ifdef _WIN32
+  FILE *file;
+  if (fopen_s(&file, os_name.c_str(), "w") != 0) {
+#else
   FILE *file = fopen(os_name.c_str(), "w");
   FILE *file = fopen(os_name.c_str(), "w");
+  if (file == NULL) {
+#endif
+    dxml_cat.error() << "Failed to open " << filename << " for writing\n";
+  }
   xnode->Print(file, 0);
   xnode->Print(file, 0);
   fclose(file);
   fclose(file);
 }
 }

+ 1 - 1
panda/src/egg/eggCompositePrimitive.h

@@ -38,7 +38,7 @@ PUBLISHED:
   MAKE_SEQ(get_components, get_num_components, get_component);
   MAKE_SEQ(get_components, get_num_components, get_component);
   INLINE void set_component(int i, const EggAttributes *attrib);
   INLINE void set_component(int i, const EggAttributes *attrib);
 
 
-  MAKE_PROPERTY(components, get_num_components, get_component, set_component);
+  MAKE_SEQ_PROPERTY(components, get_num_components, get_component, set_component);
 
 
   INLINE bool triangulate_into(EggGroupNode *container) const;
   INLINE bool triangulate_into(EggGroupNode *container) const;
   PT(EggCompositePrimitive) triangulate_in_place();
   PT(EggCompositePrimitive) triangulate_in_place();

+ 10 - 10
panda/src/egg2pg/eggBinner.cxx

@@ -50,16 +50,7 @@ prepare_node(EggNode *node) {
  */
  */
 int EggBinner::
 int EggBinner::
 get_bin_number(const EggNode *node) {
 get_bin_number(const EggNode *node) {
-  if (node->is_of_type(EggPrimitive::get_class_type())) {
-    return (int)BN_polyset;
-
-  } else if (node->is_of_type(EggGroup::get_class_type())) {
-    const EggGroup *group = DCAST(EggGroup, node);
-    if (group->has_lod()) {
-      return (int)BN_lod;
-    }
-
-  } else if (node->is_of_type(EggNurbsSurface::get_class_type())) {
+  if (node->is_of_type(EggNurbsSurface::get_class_type())) {
     return (int)BN_nurbs_surface;
     return (int)BN_nurbs_surface;
 
 
   } else if (node->is_of_type(EggNurbsCurve::get_class_type())) {
   } else if (node->is_of_type(EggNurbsCurve::get_class_type())) {
@@ -67,6 +58,15 @@ get_bin_number(const EggNode *node) {
 
 
   } else if (node->is_of_type(EggPatch::get_class_type())) {
   } else if (node->is_of_type(EggPatch::get_class_type())) {
     return (int)BN_patches;
     return (int)BN_patches;
+
+  } else if (node->is_of_type(EggPrimitive::get_class_type())) {
+    return (int)BN_polyset;
+
+  } else if (node->is_of_type(EggGroup::get_class_type())) {
+    const EggGroup *group = DCAST(EggGroup, node);
+    if (group->has_lod()) {
+      return (int)BN_lod;
+    }
   }
   }
 
 
   return (int)BN_none;
   return (int)BN_none;

+ 1 - 1
panda/src/egg2pg/eggLoader.cxx

@@ -2242,7 +2242,7 @@ make_vertex_data(const EggRenderState *render_state,
     PT(GeomVertexArrayFormat) anim_array_format = new GeomVertexArrayFormat;
     PT(GeomVertexArrayFormat) anim_array_format = new GeomVertexArrayFormat;
     anim_array_format->add_column
     anim_array_format->add_column
       (InternalName::get_transform_blend(), 1,
       (InternalName::get_transform_blend(), 1,
-       Geom::NT_uint16, Geom::C_index);
+       Geom::NT_uint16, Geom::C_index, 0, 2);
     temp_format->add_array(anim_array_format);
     temp_format->add_array(anim_array_format);
 
 
     pmap<string, BitArray> slider_names;
     pmap<string, BitArray> slider_names;

+ 4 - 0
panda/src/event/pythonTask.cxx

@@ -319,12 +319,14 @@ __getattr__(PyObject *attr) const {
  */
  */
 int PythonTask::
 int PythonTask::
 __traverse__(visitproc visit, void *arg) {
 __traverse__(visitproc visit, void *arg) {
+/*
   Py_VISIT(_function);
   Py_VISIT(_function);
   Py_VISIT(_args);
   Py_VISIT(_args);
   Py_VISIT(_upon_death);
   Py_VISIT(_upon_death);
   Py_VISIT(_owner);
   Py_VISIT(_owner);
   Py_VISIT(__dict__);
   Py_VISIT(__dict__);
   Py_VISIT(_generator);
   Py_VISIT(_generator);
+*/
   return 0;
   return 0;
 }
 }
 
 
@@ -333,12 +335,14 @@ __traverse__(visitproc visit, void *arg) {
  */
  */
 int PythonTask::
 int PythonTask::
 __clear__() {
 __clear__() {
+/*
   Py_CLEAR(_function);
   Py_CLEAR(_function);
   Py_CLEAR(_args);
   Py_CLEAR(_args);
   Py_CLEAR(_upon_death);
   Py_CLEAR(_upon_death);
   Py_CLEAR(_owner);
   Py_CLEAR(_owner);
   Py_CLEAR(__dict__);
   Py_CLEAR(__dict__);
   Py_CLEAR(_generator);
   Py_CLEAR(_generator);
+*/
   return 0;
   return 0;
 }
 }
 
 

+ 10 - 0
panda/src/express/hashVal.I

@@ -184,6 +184,16 @@ INLINE void HashVal::
 hash_string(const string &data) {
 hash_string(const string &data) {
   hash_buffer(data.data(), data.length());
   hash_buffer(data.data(), data.length());
 }
 }
+
+/**
+ * Generates the hash value by hashing the indicated data.  This method is
+ * only defined if we have the OpenSSL library (which provides md5
+ * functionality) available.
+ */
+INLINE void HashVal::
+hash_bytes(const pvector<unsigned char> &data) {
+  hash_buffer((const char *)&data[0], data.size());
+}
 #endif  // HAVE_OPENSSL
 #endif  // HAVE_OPENSSL
 
 
 /**
 /**

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