2
0
Эх сурвалжийг харах

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

rdb 9 жил өмнө
parent
commit
731d0eb1dd
100 өөрчлөгдсөн 1602 нэмэгдсэн , 1080 устгасан
  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.task.Task import Task
-from pandac.PandaModules import *
+from panda3d.core import *
 from . import GravityWalker
 
 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.showbase.InputStateGlobal import inputState
 from direct.task.Task import Task
-from pandac.PandaModules import *
+from panda3d.core import *
 
 class NonPhysicsWalker(DirectObject.DirectObject):
     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
 
 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 direct.task import Task
 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.directnotify.DirectNotifyGlobal import directNotify
 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.interval.IntervalGlobal import *
 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
 
 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.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.task import Task
 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 GridParent
 

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

@@ -35,7 +35,11 @@ class DistributedObjectGlobalUD(DistributedObjectUD):
     def __execMessage(self, message):
         if not self.ExecNamespace:
             # 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()
 
         # 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.distributed.DistributedObjectBase import DistributedObjectBase
 from direct.showbase import PythonUtil
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 #from PyDatagram import PyDatagram
 #from PyDatagramIterator import PyDatagramIterator
 

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

@@ -1,6 +1,7 @@
 """DistributedSmoothNode module: contains the DistributedSmoothNode class"""
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from .ClockDelta import *
 from . import DistributedNode
 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.
 """
 
-from pandac.PandaModules import *
+from panda3d.core import *
+from panda3d.direct import *
 from .MsgTypes import *
 from direct.showbase.PythonUtil import *
 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

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

@@ -1,6 +1,7 @@
 """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.task import Task
 from direct.directnotify import DirectNotifyGlobal

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

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

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

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

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

@@ -149,7 +149,7 @@ class FSM(DirectObject):
 
     def __init__(self, name):
         self.fsmLock = RLock()
-        self.name = name
+        self._name = name
         self.stateArray = []
         self._serialNum = FSM.SerialNum
         FSM.SerialNum += 1
@@ -185,7 +185,7 @@ class FSM(DirectObject):
         # the messenger on every state change. The new and old states are
         # accessible as self.oldState and self.newState, and the transition
         # 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):
         if not self.state:
@@ -240,7 +240,7 @@ class FSM(DirectObject):
         try:
             assert isinstance(request, str)
             self.notify.debug("%s.forceTransition(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
 
             if not self.state:
                 # Queue up the request.
@@ -268,7 +268,7 @@ class FSM(DirectObject):
         try:
             assert isinstance(request, str)
             self.notify.debug("%s.demand(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
             if not self.state:
                 # Queue up the request.
                 self.__requestQueue.append(PythonUtil.Functor(
@@ -307,7 +307,7 @@ class FSM(DirectObject):
         try:
             assert isinstance(request, str)
             self.notify.debug("%s.request(%s, %s" % (
-                self.name, request, str(args)[1:]))
+                self._name, request, str(args)[1:]))
 
             filter = self.getCurrentFilter()
             result = filter(request, args)
@@ -385,7 +385,7 @@ class FSM(DirectObject):
 
         # In either case, we quietly ignore unhandled command
         # (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
 
     def filterOff(self, request, args):
@@ -444,7 +444,7 @@ class FSM(DirectObject):
         # Internal function to change unconditionally to the indicated
         # 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.newState = newState
@@ -476,7 +476,7 @@ class FSM(DirectObject):
 
         if self.__requestQueue:
             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()
 
     def __callEnterFunc(self, name, *args):
@@ -525,9 +525,9 @@ class FSM(DirectObject):
         try:
             className = self.__class__.__name__
             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:
-                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
         finally:
             self.fsmLock.release()

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

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

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

@@ -77,9 +77,14 @@ class SeqValue:
         """ Compares to another seq 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):
         return bool(self.value)
 
     def __str__(self):
         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.
     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.
     import direct
@@ -241,7 +243,10 @@ class models(package):
     # we assume this is the models directory.
     pathname = getModelPath().findFile('cmss12.egg')
     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):

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

@@ -217,6 +217,24 @@ run_python() {
     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.
   PyObject *result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
   if (result == NULL) {

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

@@ -106,10 +106,12 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
 
     def __repr__(self):
         outStr = 'DistancePhasedObject('
-        outStr += '%s' % repr(self.getName())
+        outStr += repr(self.getName())
         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 += ')'
         return outStr
 
@@ -287,10 +289,12 @@ class BufferedDistancePhasedNode(DistancePhasedNode):
 
     def __repr__(self):
         outStr = 'BufferedDistancePhasedNode('
-        outStr += '%s' % repr(self.getName())
+        outStr += repr(self.getName())
         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 += ')'
         return outStr
 

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

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

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

@@ -1,6 +1,6 @@
 # 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.Job import Job
 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
 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
 
 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.
 """
 
-from pandac.PandaModules import *
+from panda3d.core import *
 from direct.task import Task
 
 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.directnotify import DirectNotifyGlobal
-from pandac.PandaModules import *
+from panda3d.core import *
 from . import 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
         ## set or base.startWx() is called.
         self.wxApp = None
+        self.wxAppCreated = False
         self.tkRoot = None
+        self.tkRootCreated = False
 
         # This is used for syncing multiple PCs in a distributed cluster
         try:
@@ -259,6 +261,17 @@ class ShowBase(DirectObject.DirectObject):
             random.seed(seed)
             #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.
         if self.windowType != 'none':
             props = WindowProperties.getDefault()
@@ -2821,7 +2834,7 @@ class ShowBase(DirectObject.DirectObject):
         updated, but wxPython owns the main loop (which seems to make
         it happier than the other way around). """
 
-        if self.wxApp:
+        if self.wxAppCreated:
             # Don't do this twice.
             return
 
@@ -2831,8 +2844,9 @@ class ShowBase(DirectObject.DirectObject):
         # by modulefinder when packaging an application.
         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):
             # Put wxPython in charge of the main loop.  It really
@@ -2867,6 +2881,7 @@ class ShowBase(DirectObject.DirectObject):
                 return task.again
 
             self.taskMgr.add(wxLoop, 'wxLoop')
+        self.wxAppCreated = True
 
     def __wxTimerCallback(self, event):
         if Thread.getCurrentThread().getCurrentTask():
@@ -2901,7 +2916,7 @@ class ShowBase(DirectObject.DirectObject):
         updated, but Tkinter owns the main loop (which seems to make
         it happier than the other way around). """
 
-        if self.tkRoot:
+        if self.tkRootCreated:
             # Don't do this twice.
             return
 
@@ -2911,7 +2926,8 @@ class ShowBase(DirectObject.DirectObject):
         Pmw = importlib.import_module('Pmw')
 
         # Create a new Tk root.
-        self.tkRoot = Pmw.initialise()
+        if not self.tkRoot:
+            self.tkRoot = Pmw.initialise()
         builtins.tkroot = self.tkRoot
 
         init_app_for_gui()
@@ -2947,6 +2963,7 @@ class ShowBase(DirectObject.DirectObject):
                 return task.again
 
             self.taskMgr.add(tkLoop, 'tkLoop')
+        self.tkRootCreated = True
 
     def __tkTimerCallback(self):
         if not Thread.getCurrentThread().getCurrentTask():

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

@@ -2,6 +2,7 @@ __all__ = ['register', 'sharedPackages',
            'reloadSharedPackage', 'reloadSharedPackages']
 
 from panda3d.core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
+from direct.stdpy.file import open
 import sys
 import marshal
 import imp
@@ -173,10 +174,7 @@ class VFSLoader:
         filename = Filename(self.filename)
         filename.setExtension('py')
         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):
         """ 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:
                 filename += '.py'
-                stream = StringStream('')
+                stream = StringStream(b'')
                 if multifile.findSubfile(filename) < 0:
                     multifile.addSubfile(filename, stream, 0)
                     multifile.flush()

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

@@ -1976,9 +1976,9 @@ class ParticlePanel(AppShell):
         self.particles.renderer.setAlphaDisable(
             self.getVariable('Sprite Renderer', 'Alpha Disable').get())
     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']):
             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  ------------------------
 
 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,
      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,
     1055,  1054,  1079,  1078,  1106,  1105,  1136,  1135,  1154,  1153,
     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,
     2722,  -703,  -703,    62,  -703,  -703,  -703,  -703,    66,    48,
      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,
     -703,  -703,  -703,  -703,  -703,  -703,  2822,  4474,  2822,  2822,
     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,
      557,   557,   557,   557,   265,  2822,  2822,  -703,  -703,   558,
     -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,
     -703,  -703,  -703,  -703,   601,   586,   611,  -703,  -703,  4682,
     -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,
      358,   325,   357,   352,   349,   348,   351,   329,     0,   330,
      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,   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,
        0,     0,   553,     0,     0,   281,     0,   680,   680,     0,
        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,
      680,   680,   680,   680,     0,   290,   248,   680,   673,   674,
      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,
      314,     0,   270,     0,   492,   491,     0,     0,     0,     0,
        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,
      253,   240,     0,   249,     0,   250,   252,   251,   179,   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,
-       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,
        0,     0,     0,   545,   548,   551,     0,   555,   556,   547,
      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,
      231,   232,   234,   233,     0,     0,   680,   214,   194,   255,
      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,
      653,   652,     0,     0,     0,   644,     0,     0,     0,     0,
        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,
        0,   302,   661,   680,     0,   680,     0,     0,     0,     0,
        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,     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,   680,
        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,
        0,     0,     0,   216,     0,     0,   680,   237,   321,     0,
      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,
        0,     0,     0,     0,     0,   193,   495,     0,    78,     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,
      607,     0,   611,   612,   602,     0,   638,   637,    88,   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,
      520,   521,   522,   523,   524,   530,     0,   514,   515,   516,
      512,   513,   509,   510,   511,   529,   528,     0,     0,    79,
        0,     0,   610,     0,     0,   636,   680,     0,   680,    91,
      213,   172,     0,   259,   258,   257,   238,     0,     0,     0,
        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,
-     680,    87,    34,    32,   499,   498,   500,   497,    89
+     680,    87,    33,    31,   499,   498,   500,   497,    89
 };
 
   /* YYPGOTO[NTERM-NUM].  */
@@ -1907,24 +1907,24 @@ static const yytype_int16 yytable[] =
       86,    87,   108,   109,     0,     0,     0,   110,     0,    88,
        0,     0,   111,   112,     0,   113,     0,    89,     0,    90,
       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,   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,     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,
       -1,    -1,   117,   118,    -1,   120,    -1,    66,    -1,    68,
       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,   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,    -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,
      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,   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,   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,
      168,   170,   169,   171,   169,   169,   172,   172,   173,   173,
      175,   174,   176,   174,   178,   177,   179,   177,   180,   177,
@@ -2706,12 +2706,12 @@ static const yytype_uint16 yyr1[] =
 static const yytype_uint8 yyr2[] =
 {
        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,
        0,     6,     0,     6,     0,     7,     0,    11,     0,    12,
        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  */
     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) {
     yyerror("Unclosed __begin_publish", publish_loc);
@@ -3614,8 +3614,8 @@ yyreduce:
 #line 3615 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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) {
     yyerror("Unmatched __end_publish", (yylsp[0]));
@@ -3627,16 +3627,16 @@ yyreduce:
 #line 3628 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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);
 }
 #line 3636 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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) {
     current_scope->set_current_vis(V_published);
@@ -3647,24 +3647,24 @@ yyreduce:
 #line 3648 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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);
 }
 #line 3656 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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);
 }
 #line 3664 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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);
@@ -3678,8 +3678,8 @@ yyreduce:
 #line 3679 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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);
   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  */
     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();
   if (result._type == CPPExpression::RT_error) {
@@ -3935,8 +3935,8 @@ yyreduce:
 #line 3936 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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.
   CPPExpression::Result result = (yyvsp[-2].u.expr)->evaluate();
@@ -3949,8 +3949,8 @@ yyreduce:
 #line 3950 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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"),
                                      V_public);
@@ -3959,8 +3959,8 @@ yyreduce:
 #line 3960 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
   pop_scope();
@@ -3968,24 +3968,24 @@ yyreduce:
 #line 3969 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 3977 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 3985 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
   if ((yyvsp[-1].str) == "C") {
@@ -3999,96 +3999,96 @@ yyreduce:
 #line 4000 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4008 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4016 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4024 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4032 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4040 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4048 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4056 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4064 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4072 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4080 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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;
 }
 #line 4088 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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.
   (yyval.u.integer) = (yyvsp[0].u.integer);
@@ -4096,16 +4096,16 @@ yyreduce:
 #line 4097 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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. */
 }
 #line 4105 "built/tmp/cppBison.yxx.c" /* yacc.c:1646  */
     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
   // 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  */
     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) {
     (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  */
     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) {
     (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
         | extern_c
         | namespace_declaration
-        | using_declaration
         | friend_declaration
         | KW_TYPEDEF typedef_declaration
         | KW_BEGIN_PUBLISH
@@ -891,6 +890,7 @@ type_like_declaration:
     $2->set_initializer($3);
   }
 }
+        | using_declaration
         ;
 
 multiple_var_declaration:

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

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

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

@@ -18,6 +18,7 @@
 #include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppExtensionType.h"
+#include "cppEnumType.h"
 #include "cppInstance.h"
 #include "cppInstanceIdentifier.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) {
   CPPTypedefType *def = decl->as_typedef_type();
   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();
     if (et != NULL) {
       define_extension_type(et, error_sink);
     }
-
     return;
   }
 

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

@@ -62,6 +62,8 @@ public:
                                CPPPreprocessor *preprocessor,
                                const cppyyltype &pos);
   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,
                                      CPPPreprocessor *error_sink = NULL);
   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
         // 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()) {
             rep->_template_scope = (CPPTemplateScope *)NULL;
             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);
 }
 
+/**
+ *
+ */
+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,
                                const cppyyltype &pos);
   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,
                                      CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);

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

@@ -14,6 +14,8 @@
 #include "cppTypedefType.h"
 #include "cppIdentifier.h"
 #include "cppInstanceIdentifier.h"
+#include "cppTemplateScope.h"
+#include "indent.h"
 
 /**
  *
@@ -193,6 +195,17 @@ is_fully_specified() const {
     _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 (_using) {
       // 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 << " = ";
       _type->output(out, 0, scope, false);
     } else {

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

@@ -21,7 +21,9 @@ class CPPIdentifier;
 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 {
 public:
@@ -46,6 +48,11 @@ public:
 
   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,
                                           CPPScope *current_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 */

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 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_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__)
-#undef USE_STL_ALLOCATOR  /* Don't try to parse these template classes in interrogate. */
 #define EXTENSION(x) __extension x
 #define EXTEND __extension
 #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
 // MemoryHook.
 
+#define DLMALLOC_EXPORT static
 #define USE_DL_PREFIX 1
 #define NO_MALLINFO 1
 #ifdef _DEBUG
   #define DEBUG 1
 #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
-#include "dlmalloc.h"
+
 #include "dlmalloc_src.cxx"
 
 #define call_malloc dlmalloc

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

@@ -32,7 +32,7 @@
  * 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
 // kind of syntax this STL library wants, or we're compiling with OPTIMIZE 4),
 // then simply use the standard allocator.

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

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

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

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

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

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

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

@@ -25,6 +25,12 @@
 // definition.
 #define pvector vector
 
+#elif defined(CPPPARSER)
+// Simplified definition to speed up Interrogate parsing.
+template<class Type>
+class pvector : public vector<Type> {
+};
+
 #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.
     int hash = (clock() * time(NULL)) & 0xffffff;
     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.set_type(type);
   } while (result.exists());

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

@@ -133,7 +133,8 @@ check_protocols() {
     if (func->_ifunc.get_name() == "__traverse__") {
       // If we have a method named __traverse__, we implement Python's cyclic
       // 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) {

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

@@ -2890,10 +2890,12 @@ write_module_class(ostream &out, Object *obj) {
   }
 
   // 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;
-  write_function_slot(out, 4, slots, "tp_clear");
+  out << "    0, // tp_clear\n";
+  //write_function_slot(out, 4, slots, "tp_clear");
 
   // richcmpfunc tp_richcompare;
   if (has_local_richcompare) {
@@ -4794,6 +4796,26 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       clear_error = true;
       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)) {
       if (args_type == AT_single_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_wchar_pointer(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,
     // defined in py_panda.h.
     indent(out, indent_level)
@@ -6241,7 +6264,7 @@ write_getset(ostream &out, Object *obj, Property *property) {
       out <<
         "  " << cClassName  << " *local_this = NULL;\n"
         "  if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"
-        "    return NULL;\n"
+        "    return -1;\n"
         "  }\n"
         "  return (Py_ssize_t)" << len_remap->get_call_str("local_this", pexprs) << ";\n";
     } else {
@@ -6713,6 +6736,8 @@ is_cpp_type_legal(CPPType *in_ctype) {
     return true;
   } else if (TypeManager::is_basic_string_wchar(type)) {
     return true;
+  } else if (TypeManager::is_vector_unsigned_char(type)) {
+    return true;
   } else if (TypeManager::is_simple(type)) {
     return true;
   } 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;
   }
 
-  // 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()) {
     // 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);
 }
 
+/**
+ * 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.
  */

+ 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_ptr_to_basic_string_wchar(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_bool(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) {
   InterrogateModuleDef *def = new InterrogateModuleDef;
   memset(def, 0, sizeof(InterrogateModuleDef));
+#ifdef _WIN32
+  def->database_filename = _strdup(database_filename);
+#else
   def->database_filename = strdup(database_filename);
+#endif
 
   // Don't think of this as a leak; think of it as a one-time database
   // 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.
  */
 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.");
     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,
                                             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.");
     return false;
   }
@@ -172,7 +172,6 @@ void *DTOOL_Call_GetPointerThis(PyObject *self) {
   return NULL;
 }
 
-#ifndef NDEBUG
 /**
  * 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
@@ -193,7 +192,6 @@ bool _Dtool_CheckErrorOccurred() {
   }
   return false;
 }
-#endif  // NDEBUG
 
 /**
  * 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
 
+// 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;
 
 // 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;
 
+struct sockaddr;
 struct sockaddr_in;
+struct sockaddr_in6;
+struct sockaddr_storage;
 
 #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()) {
         // Format a timestamp to include as a prefix as well.
         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];
-        strftime(buffer, 128, ":%m-%d-%Y %H:%M:%S ", ptm);
+        strftime(buffer, 128, ":%m-%d-%Y %H:%M:%S ", &atm);
         nout << buffer;
       }
 

+ 12 - 8
makepanda/makepanda.py

@@ -46,7 +46,7 @@ CFLAGS=""
 CXXFLAGS=""
 LDFLAGS=""
 RTDIST=0
-RTDIST_VERSION="dev"
+RTDIST_VERSION=None
 RUNTIME=0
 DISTRIBUTOR=""
 VERSION=None
@@ -163,13 +163,13 @@ def usage(problem):
 def parseopts(args):
     global INSTALLER,RTDIST,RUNTIME,GENMAN,DISTRIBUTOR,VERSION
     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
     longopts = [
         "help","distributor=","verbose","runtime","osxtarget=",
         "optimize=","everything","nothing","installer","rtdist","nocolor",
         "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",
         "universal", "target=", "arch=", "git-commit="]
     anything = 0
@@ -214,6 +214,7 @@ def parseopts(args):
             elif (option=="--rpmrelease"): RPMRELEASE=value
             elif (option=="--git-commit"): GIT_COMMIT=value
             elif (option=="--p3dsuffix"): P3DSUFFIX=value
+            elif (option=="--rtdist-version"): RTDIST_VERSION=value
             # Backward compatibility, OPENGL was renamed to GL
             elif (option=="--use-opengl"): PkgEnable("GL")
             elif (option=="--no-opengl"): PkgDisable("GL")
@@ -400,9 +401,12 @@ if (RUNTIME or RTDIST):
 
 if DISTRIBUTOR == "":
     DISTRIBUTOR = "makepanda"
-else:
+elif not RTDIST_VERSION:
     RTDIST_VERSION = DISTRIBUTOR.strip() + "_" + MAJOR_VERSION
 
+if not RTDIST_VERSION:
+    RTDIST_VERSION = "dev"
+
 if not IsCustomOutputDir():
     if GetTarget() == "windows" and GetTargetArch() == 'x64':
         outputdir_suffix += '_x64'
@@ -787,9 +791,9 @@ if (COMPILER=="GCC"):
         SmartPkgEnable("ARTOOLKIT", "",          ("AR"), "AR/ar.h")
         SmartPkgEnable("FCOLLADA",  "",          ChooseLib(fcollada_libs, "FCOLLADA"), ("FCollada", "FCollada/FCollada.h"))
         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("FMODEX",    "",          ("fmodex"), ("fmodex", "fmodex/fmod.h"))
         SmartPkgEnable("FREETYPE",  "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h"))
@@ -1058,7 +1062,7 @@ def CompileCxx(obj,src,opts):
             cmd = "cl "
             if GetTargetArch() == 'x64':
                 cmd += "/favor:blend "
-            cmd += "/wd4996 /wd4275 /wd4267 /wd4101 /wd4273 "
+            cmd += "/wd4996 /wd4275 /wd4273 "
 
             # Enable Windows 7 interfaces if we need Touchinput.
             if PkgSkip("TOUCHINPUT") == 0:

+ 21 - 14
makepanda/makepandacore.py

@@ -16,10 +16,10 @@ else:
     import cPickle as pickle
     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_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"])
 STARTTIME = time.time()
 MAINTHREAD = threading.currentThread()
@@ -76,6 +76,7 @@ MAYAVERSIONINFO = [("MAYA6",   "6.0"),
                    ("MAYA2014","2014"),
                    ("MAYA2015","2015"),
                    ("MAYA2016","2016"),
+                   ("MAYA20165","2016.5")
 ]
 
 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(" "):
         if (l.startswith("-D")):
             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]] = ""
             else:
                 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)))
         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
     if (pkg in PkgListGet() and PkgSkip(pkg)):
         return
@@ -1482,16 +1488,12 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
 
     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 framework and os.path.isdir(os.path.join(pkg_dir, framework + ".framework")):
             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)
             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)
             else:
                 # This is for backward compatibility - in the thirdparty dir,
                 # we kept some libs with "panda" prefix, like libpandatiff.
                 location = LocateLibrary("panda" + libname, lpath, prefer_static=True)
                 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)
                 else:
                     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
     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",    SDK["VISUALSTUDIO"] + "Common7\\IDE")

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

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

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

@@ -25,4 +25,24 @@
     [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

+ 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 "
           "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
 ("win-size", "800 600",
  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 alpha_scale_via_texture;
 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_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.
   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();
 
 #ifdef DO_PSTATS

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

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

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

@@ -18,6 +18,14 @@ INLINE BioPtr::
 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 "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
  * it the server and port name from the indicated URL.  It doesn't call
  * BIO_do_connect(), though.
  */
 BioPtr::
-BioPtr(const URLSpec &url) {
+BioPtr(const URLSpec &url) : _connecting(false) {
   if (url.get_scheme() == "file") {
     // We're just reading a disk file.
     string filename = URLSpec::unquote(url.get_path());
@@ -48,12 +81,141 @@ BioPtr(const URLSpec &url) {
     _bio = BIO_new_file(filename.c_str(), "rb");
 
   } 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();
     _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 (downloader_cat.is_debug() && !_server_name.empty()) {
       downloader_cat.debug()
-        << "Dropping connection to " << _server_name << ":" << _port << "\n";
+        << "Dropping connection to " << _server_name << " port " << _port << "\n";
     }
 
     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 "openssl/ssl.h"
 
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
 class URLSpec;
 
 /**
@@ -41,6 +49,11 @@ public:
   BioPtr(const URLSpec &url);
   virtual ~BioPtr();
 
+  void set_nbio(bool nbio);
+  bool connect();
+
+  INLINE bool should_retry() const;
+
   INLINE BIO &operator *() const;
   INLINE BIO *operator -> () const;
   INLINE operator BIO * () const;
@@ -55,6 +68,9 @@ private:
   BIO *_bio;
   string _server_name;
   int _port;
+  struct sockaddr_storage _addr;
+  socklen_t _addrlen;
+  bool _connecting;
 };
 
 #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 "
           "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) {
   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 EXPCL_PANDAEXPRESS ConfigVariableInt tcp_header_size;
+extern EXPCL_PANDAEXPRESS ConfigVariableBool support_ipv6;
 
 extern EXPCL_PANDAEXPRESS void init_libdownloader();
 

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

@@ -375,26 +375,28 @@ run() {
       }
 
       // No connection.  Attempt to establish one.
+      URLSpec url;
       if (_proxy.empty()) {
-        _bio = new BioPtr(_request.get_url());
+        url = _request.get_url();
       } else {
-        _bio = new BioPtr(_proxy);
+        url = _proxy;
       }
+      _bio = new BioPtr(url);
       _source = new BioStreamPtr(new BioStream(_bio));
       if (_nonblocking) {
-        BIO_set_nbio(*_bio, 1);
+        _bio->set_nbio(true);
       }
 
       if (downloader_cat.is_debug()) {
         if (_connect_count > 0) {
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Reconnecting to " << _bio->get_server_name() << ":"
+            << "Reconnecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
         } else {
           downloader_cat.debug()
             << _NOTIFY_HTTP_CHANNEL_ID
-            << "Connecting to " << _bio->get_server_name() << ":"
+            << "Connecting to " << _bio->get_server_name() << " port "
             << _bio->get_port() << "\n";
         }
       }
@@ -941,14 +943,14 @@ bool HTTPChannel::
 run_connecting() {
   _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;
       return false;
     }
     downloader_cat.info()
       << _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";
     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
     _status_entry._status_code = SC_no_connection;
@@ -959,7 +961,7 @@ run_connecting() {
   if (downloader_cat.is_debug()) {
     downloader_cat.debug()
       << _NOTIFY_HTTP_CHANNEL_ID
-      << "Connected to " << _bio->get_server_name() << ":"
+      << "Connected to " << _bio->get_server_name() << " port "
       << _bio->get_port() << "\n";
   }
 
@@ -1362,6 +1364,10 @@ run_socks_proxy_connect_reply() {
     total_bytes += (unsigned int)reply[4];
     break;
 
+  case 0x04:  // IPv6
+    total_bytes += 16;
+    break;
+
   default:
     downloader_cat.info()
       << _NOTIFY_HTTP_CHANNEL_ID
@@ -1396,6 +1402,18 @@ run_socks_proxy_connect_reply() {
     case 0x03:  // DNS
       connect_host = string(&reply[5], (unsigned int)reply[4]);
       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 =
@@ -2742,8 +2760,8 @@ server_getline(string &str) {
         }
         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
           << "recv: " << str << "\n";
       }
@@ -2915,7 +2933,7 @@ server_send(const string &str, bool secret) {
   }
 
 #ifndef NDEBUG
-  if (!secret && downloader_cat.is_debug()) {
+  if (!secret && downloader_cat.is_spam()) {
     show_send(str.substr(0, write_count));
   }
 #endif
@@ -3486,14 +3504,19 @@ make_header() {
 
   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
       // 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
       // 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";
     if (!get_persistent_connection()) {
@@ -3703,14 +3726,14 @@ show_send(const string &message) {
   size_t newline = message.find('\n', start);
   while (newline != string::npos) {
     // Assume every \n is preceded by a \r.
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "send: " << message.substr(start, newline - start - 1) << "\n";
     start = newline + 1;
     newline = message.find('\n', start);
   }
 
   if (start < message.length()) {
-    downloader_cat.debug()
+    downloader_cat.spam()
       << "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);
     _time -= tp->tm_gmtoff;
 #elif defined(_WIN32)
-    extern long int _timezone;
-    _time -= _timezone;
+    long int timezone;
+    _get_timezone(&timezone);
+    _time -= timezone;
 #else
     extern long int timezone;
     _time -= timezone;

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

@@ -12,6 +12,7 @@
  */
 
 #include "multiplexStreamBuf.h"
+#include "lightMutexHolder.h"
 
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #define WINDOWS_LEAN_AND_MEAN
@@ -113,10 +114,8 @@ void MultiplexStreamBuf::
 add_output(MultiplexStreamBuf::BufferType buffer_type,
            MultiplexStreamBuf::OutputType output_type,
            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.
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
   Output o;
   o._buffer_type = buffer_type;
@@ -133,9 +132,7 @@ add_output(MultiplexStreamBuf::BufferType buffer_type,
  */
 void MultiplexStreamBuf::
 flush() {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
   write_chars("", 0, true);
 }
@@ -146,9 +143,7 @@ flush() {
  */
 int MultiplexStreamBuf::
 overflow(int ch) {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
   streamsize n = pptr() - pbase();
 
@@ -172,9 +167,7 @@ overflow(int ch) {
  */
 int MultiplexStreamBuf::
 sync() {
-#ifdef OLD_HAVE_IPC
-  mutex_lock m(_lock);
-#endif
+  LightMutexHolder holder(_lock);
 
   streamsize n = pptr() - pbase();
 
@@ -242,5 +235,4 @@ write_chars(const char *start, int length, bool flush) {
       break;
     }
   }
-
 }

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

@@ -17,6 +17,7 @@
 #include "pandabase.h"
 
 #include "pvector.h"
+#include "lightMutex.h"
 #include <stdio.h>
 
 /**
@@ -69,6 +70,7 @@ private:
   typedef pvector<Output> Outputs;
   Outputs _outputs;
 
+  LightMutex _lock;
   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);
 }
 
-/**
- *
- */
-INLINE URLSpec::
-URLSpec(const URLSpec &copy) {
-  (*this) = copy;
-}
-
 /**
  *
  */
@@ -40,7 +32,7 @@ operator = (const string &url) {
  */
 INLINE bool URLSpec::
 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::
 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::
 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::
 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::
 empty() const {
   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();
 }
 
+/**
+ *
+ */
+INLINE size_t URLSpec::
+size() const {
+  return _url.size();
+}
+
 /**
  *
  */
 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];
 }
 

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

@@ -12,10 +12,11 @@
  */
 
 #include "urlSpec.h"
+#include "filename.h"
+#include "string_utils.h"
 
 #include <ctype.h>
 
-
 /**
  *
  */
@@ -35,24 +36,88 @@ URLSpec() {
   _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
  * specified.
  */
-int URLSpec::
+uint16_t URLSpec::
 get_port() const {
   if (has_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,
  * followed by the port number.  If the port number is not explicitly given in
  * 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::
 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()) {
-    return _url.substr(_server_start, _port_end - _server_start);
+    strm << ":" << get_port();
   }
-  ostringstream strm;
-  strm << get_server() << ":" << get_port();
   return strm.str();
 }
 
@@ -285,7 +361,15 @@ set_username(const string &username) {
   if (!username.empty()) {
     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()) {
     authority += ":";
     authority += get_port_str();
@@ -296,6 +380,8 @@ set_username(const string &username) {
 
 /**
  * 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::
 set_server(const string &server) {
@@ -307,7 +393,14 @@ set_server(const string &server) {
   if (has_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()) {
     authority += ":";
     authority += get_port_str();
@@ -329,7 +422,14 @@ set_port(const string &port) {
   if (has_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()) {
     authority += ":";
@@ -344,16 +444,15 @@ set_port(const string &port) {
  * number.
  */
 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.
  * The input string should be of the form "server:port", or just "server" to
  * make the port number implicit.
+ * Any IPv6 address must be enclosed in square brackets.
  */
 void URLSpec::
 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?
   _flags = 0;
   _port = 0;
@@ -781,18 +892,39 @@ parse_authority() {
     _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;
-    _server_end = colon;
-    _port_start = colon + 1;
 
     // Decode the port into an integer.  Don't bother to error check if it's
     // not really an integer.
     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.

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

@@ -17,6 +17,8 @@
 #include "pandabase.h"
 #include "pnotify.h"
 
+class Filename;
+
 /**
  * A container for a URL, e.g.  "http://server:port/path".
  *
@@ -27,14 +29,14 @@ class EXPCL_PANDAEXPRESS URLSpec {
 PUBLISHED:
   URLSpec();
   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);
-  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 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_authority() const;
@@ -49,7 +51,7 @@ PUBLISHED:
   INLINE string get_username() const;
   INLINE string get_server() const;
   INLINE string get_port_str() const;
-  int get_port() const;
+  uint16_t get_port() const;
   string get_server_and_port() const;
   bool is_default_port() const;
   static int get_default_port_for_scheme(const string &scheme);
@@ -65,7 +67,7 @@ PUBLISHED:
   void set_username(const string &username);
   void set_server(const string &server);
   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_path(const string &path);
   void set_query(const string &query);
@@ -75,8 +77,10 @@ PUBLISHED:
   INLINE operator const string & () const;
   INLINE const char *c_str() const;
   INLINE bool empty() const;
+  INLINE operator bool() 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);
   void output(ostream &out) const;
@@ -86,6 +90,16 @@ PUBLISHED:
   static string unquote(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:
   void parse_authority();
 
@@ -100,7 +114,7 @@ private:
   };
 
   string _url;
-  int _port;
+  uint16_t _port;
   int _flags;
 
   size_t _scheme_end;

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

@@ -18,6 +18,7 @@
 #include "filename.h"
 #include "pset.h"
 #include "vector_string.h"
+#include "virtualFileSystem.h"
 #include <stdio.h>
 #include <time.h>
 
@@ -631,8 +632,17 @@ list_files(const vector_string &params) {
     cerr << multifile_name << " not found.\n";
     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;
-  if (!multifile->open_read(multifile_name)) {
+  if (!multifile->open_read(new IStreamWrapper(istr, true), true)) {
     cerr << "Unable to open " << multifile_name << " for reading.\n";
     return false;
   }

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

@@ -3798,7 +3798,14 @@ do_issue_blending() {
   case TransparencyAttrib::M_multisample_mask:
   case TransparencyAttrib::M_dual:
     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_SRCBLEND, D3DBLEND_SRCALPHA);
     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

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

@@ -94,7 +94,15 @@ BEGIN_PUBLISH
 void
 print_xml_to_file(const Filename &filename, TiXmlNode *xnode) {
   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");
+  if (file == NULL) {
+#endif
+    dxml_cat.error() << "Failed to open " << filename << " for writing\n";
+  }
   xnode->Print(file, 0);
   fclose(file);
 }

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

@@ -38,7 +38,7 @@ PUBLISHED:
   MAKE_SEQ(get_components, get_num_components, get_component);
   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;
   PT(EggCompositePrimitive) triangulate_in_place();

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

@@ -50,16 +50,7 @@ prepare_node(EggNode *node) {
  */
 int EggBinner::
 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;
 
   } 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())) {
     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;

+ 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;
     anim_array_format->add_column
       (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);
 
     pmap<string, BitArray> slider_names;

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

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

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

@@ -184,6 +184,16 @@ INLINE void HashVal::
 hash_string(const string &data) {
   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
 
 /**

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно