Browse Source

Merge remote-tracking branch 'upstream/master' into cmake

Conflicts:
	direct/src/directnotify/DirectNotify.py
	direct/src/showbase/PythonUtil.py
Sam Edwards 11 years ago
parent
commit
d27bc99fcb
100 changed files with 2151 additions and 1468 deletions
  1. 5 8
      direct/src/actor/Actor.py
  2. 6 4
      direct/src/directscripts/packpanda.nsi
  3. 0 11
      direct/src/extensions/EggGroupNode-extensions.py
  4. 0 8
      direct/src/extensions/EggPrimitive-extensions.py
  5. 0 34
      direct/src/extensions/NodePathCollection-extensions.py
  6. 0 6
      direct/src/extensions/OdeBody-extensions.py
  7. 0 44
      direct/src/extensions/OdeGeom-extensions.py
  8. 0 39
      direct/src/extensions/OdeJoint-extensions.py
  9. 0 32
      direct/src/extensions/OdeSpace-extensions.py
  10. 0 15
      direct/src/extensions/Ramfile-extensions.py
  11. 0 15
      direct/src/extensions/StreamReader-extensions.py
  12. 0 16
      direct/src/extensions_native/EggGroupNode_extensions.py
  13. 0 13
      direct/src/extensions_native/EggPrimitive_extensions.py
  14. 0 31
      direct/src/extensions_native/NodePathCollection_extensions.py
  15. 0 9
      direct/src/extensions_native/NodePath_extensions.py
  16. 0 18
      direct/src/extensions_native/OdeBody_extensions.py
  17. 0 60
      direct/src/extensions_native/OdeGeom_extensions.py
  18. 0 54
      direct/src/extensions_native/OdeJoint_extensions.py
  19. 0 50
      direct/src/extensions_native/OdeSpace_extensions.py
  20. 0 16
      direct/src/extensions_native/Ramfile_extensions.py
  21. 0 16
      direct/src/extensions_native/StreamReader_extensions.py
  22. 3 2
      direct/src/interval/FunctionInterval.py
  23. 1 1
      direct/src/showbase/Loader.py
  24. 4 1
      direct/src/showbase/Messenger.py
  25. 2 4
      direct/src/showbase/PythonUtil.py
  26. 28 18
      dtool/src/interrogate/functionRemap.cxx
  27. 2 1
      dtool/src/interrogate/functionRemap.h
  28. 178 137
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  29. 4 0
      dtool/src/interrogate/interrogateBuilder.cxx
  30. 1 1
      dtool/src/interrogate/interrogate_module.cxx
  31. 3 9
      dtool/src/interrogatedb/extension.h
  32. 3 3
      dtool/src/interrogatedb/py_panda.cxx
  33. 3 0
      dtool/src/parser-inc/Python.h
  34. 1 0
      dtool/src/prc/streamReader.h
  35. BIN
      makepanda/Panda3D-tpl.dmg
  36. 8 10
      makepanda/installpanda.py
  37. 314 188
      makepanda/makepanda.py
  38. 43 23
      makepanda/makepandacore.py
  39. 14 15
      panda/src/bullet/bulletContactResult.I
  40. 75 6
      panda/src/bullet/bulletContactResult.cxx
  41. 25 5
      panda/src/bullet/bulletContactResult.h
  42. 19 9
      panda/src/bullet/bulletHelper.cxx
  43. 22 0
      panda/src/bullet/bulletManifoldPoint.cxx
  44. 3 0
      panda/src/bullet/bulletManifoldPoint.h
  45. 1 1
      panda/src/bullet/bulletSoftBodyConfig.h
  46. 52 17
      panda/src/bullet/bulletSoftBodyNode.cxx
  47. 3 0
      panda/src/bullet/bulletSoftBodyNode.h
  48. 56 7
      panda/src/bullet/bulletWorld.cxx
  49. 4 1
      panda/src/bullet/bulletWorld.h
  50. 1 1
      panda/src/chan/partGroup.h
  51. 2 1
      panda/src/cocoadisplay/Sources.pp
  52. 2 1
      panda/src/cocoadisplay/cocoaGraphicsPipe.mm
  53. 3 1
      panda/src/cocoadisplay/cocoaGraphicsWindow.h
  54. 208 46
      panda/src/cocoadisplay/cocoaGraphicsWindow.mm
  55. 21 0
      panda/src/cocoadisplay/cocoaPandaApp.h
  56. 29 0
      panda/src/cocoadisplay/cocoaPandaApp.mm
  57. 2 1
      panda/src/cocoadisplay/p3cocoadisplay_composite1.mm
  58. 2 2
      panda/src/display/Sources.pp
  59. 28 51
      panda/src/display/graphicsStateGuardian.cxx
  60. 3 5
      panda/src/display/graphicsStateGuardian.h
  61. 55 0
      panda/src/display/graphicsStateGuardian_ext.cxx
  62. 40 0
      panda/src/display/graphicsStateGuardian_ext.h
  63. 22 0
      panda/src/display/graphicsWindowInputDevice.cxx
  64. 12 10
      panda/src/display/graphicsWindowInputDevice.h
  65. 5 2
      panda/src/egg/Sources.pp
  66. 2 0
      panda/src/egg/eggGroupNode.h
  67. 51 0
      panda/src/egg/eggGroupNode_ext.cxx
  68. 40 0
      panda/src/egg/eggGroupNode_ext.h
  69. 1 1
      panda/src/egg/eggParameters.h
  70. 28 19
      panda/src/egldisplay/eglGraphicsWindow.cxx
  71. 8 0
      panda/src/event/buttonEvent.cxx
  72. 8 1
      panda/src/event/buttonEvent.h
  73. 1 1
      panda/src/event/pythonTask.cxx
  74. 9 3
      panda/src/express/Sources.pp
  75. 0 73
      panda/src/express/memoryUsagePointers.cxx
  76. 1 3
      panda/src/express/memoryUsagePointers.h
  77. 72 0
      panda/src/express/memoryUsagePointers_ext.cxx
  78. 40 0
      panda/src/express/memoryUsagePointers_ext.h
  79. 4 0
      panda/src/express/p3express_ext_composite.cxx
  80. 1 0
      panda/src/express/ramfile.h
  81. 48 0
      panda/src/express/ramfile_ext.cxx
  82. 40 0
      panda/src/express/ramfile_ext.h
  83. 48 0
      panda/src/express/streamReader_ext.cxx
  84. 40 0
      panda/src/express/streamReader_ext.h
  85. 2 0
      panda/src/express/virtualFileSystem.cxx
  86. 1 1
      panda/src/express/virtualFileSystem_ext.cxx
  87. 10 0
      panda/src/gles2gsg/gles2gsg.h
  88. 75 100
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  89. 1 0
      panda/src/glstuff/glGraphicsBuffer_src.h
  90. 19 7
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  91. 91 67
      panda/src/glstuff/glShaderContext_src.cxx
  92. 8 1
      panda/src/glstuff/glShaderContext_src.h
  93. 19 0
      panda/src/gobj/internalName.cxx
  94. 1 0
      panda/src/gobj/internalName.h
  95. 47 28
      panda/src/gobj/shader.cxx
  96. 71 67
      panda/src/gobj/shader.h
  97. 1 1
      panda/src/gobj/textureCollection.cxx
  98. 34 1
      panda/src/gobj/textureStage.I
  99. 0 3
      panda/src/gobj/textureStage.cxx
  100. 11 12
      panda/src/gobj/textureStage.h

+ 5 - 8
direct/src/actor/Actor.py

@@ -566,7 +566,7 @@ class Actor(DirectObject, NodePath):
         # and sort them every time somebody asks for the list
         self.__sortedLODNames = self.__partBundleDict.keys()
         # Reverse sort the doing a string->int
-        def sortFunc(x, y):
+        def sortKey(x):
             if not str(x).isdigit():
                 smap = {'h':3,
                         'm':2,
@@ -574,19 +574,16 @@ class Actor(DirectObject, NodePath):
                         'f':0}
 
                 """
-                sx = smap.get(x[0],None)
-                sy = smap.get(y[0],None)
+                sx = smap.get(x[0], None)
 
                 if sx is None:
                     self.notify.error('Invalid lodName: %s' % x)
-                if sy is None:
-                    self.notify.error('Invalid lodName: %s' % y)
                 """
-                return cmp(smap[y[0]], smap[x[0]])
+                return smap[x[0]]
             else:
-                return cmp (int(y), int(x))
+                return int(x)
 
-        self.__sortedLODNames.sort(sortFunc)
+        self.__sortedLODNames.sort(key=sortKey, reverse=True)
 
     def getLODNames(self):
         """

+ 6 - 4
direct/src/directscripts/packpanda.nsi

@@ -103,8 +103,6 @@ Section "${SMDIRECTORY}" SecCore
         File /r /x CVS /x Opt?-Win32 "${PSOURCE}\direct\filter\*.sha"
         SetOutPath $INSTDIR\direct
         File /r /x CVS /x Opt?-Win32 "${PSOURCE}\direct\*.py"
-        SetOutPath $INSTDIR
-        File "${PSOURCE}\panda3d.py"
         !else
         File /r /x CVS /x Opt?-Win32 "${PSOURCE}\direct\src\directscripts\*"
         SetOutPath $INSTDIR\direct\filter
@@ -112,11 +110,15 @@ Section "${SMDIRECTORY}" SecCore
         SetOutPath $INSTDIR\direct
         File /r /x CVS /x Opt?-Win32 "${PSOURCE}\direct\src\*.py"
         File "${PANDA}\tmp\__init__.py"
-        SetOutPath $INSTDIR
-        File "${PSOURCE}\direct\src\ffi\panda3d.py"
         !endif
+        Delete "$INSTDIR\panda3d.py"
+        Delete "$INSTDIR\panda3d.pyc"
+        Delete "$INSTDIR\panda3d.pyo"
         SetOutPath $INSTDIR\pandac
         File /r "${PANDA}\pandac\*.py"
+        SetOutPath $INSTDIR\panda3d
+        File /r "${PANDA}\panda3d\*.py"
+        File /r "${PANDA}\panda3d\*.pyd"
         SetOutPath $INSTDIR\python
         File /r "${PANDA}\python\*"
         RMDir /r "$SMPROGRAMS\${SMDIRECTORY}"

+ 0 - 11
direct/src/extensions/EggGroupNode-extensions.py

@@ -1,11 +0,0 @@
-
-    # For iterating over children
-    def getChildren(self):
-        """Returns a Python list of the egg node's children."""
-        result = []
-        child = self.getFirstChild()
-        while (child != None):
-            result.append(child)
-            child = self.getNextChild()
-        return result
-    

+ 0 - 8
direct/src/extensions/EggPrimitive-extensions.py

@@ -1,8 +0,0 @@
-
-    # For iterating over vertices
-    def getVertices(self):
-        """Returns a Python list of the egg primitive's vertices."""
-        result = []
-        for i in range(self.getNumVertices()):
-            result.append(self.getVertex(i))
-        return result

+ 0 - 34
direct/src/extensions/NodePathCollection-extensions.py

@@ -1,34 +0,0 @@
-
-    """
-    NodePathCollection-extensions module: contains methods to extend
-    functionality of the NodePathCollection class
-    """
-
-    # For iterating over children
-    def asList(self):
-        """Converts a NodePathCollection into a list"""
-        if self.isEmpty():
-            return []
-        else:
-            npList = []
-            for nodePathIndex in range(self.getNumPaths()):
-                npList.append(self.getPath(nodePathIndex))
-            return npList
-
-    def getTightBounds(self):
-        from pandac import Point3
-        
-        if self.getNumPaths() == 0:
-            return (Point3.Point3(0), Point3.Point3(0))
-
-        v1, v2 = self.getPath(0).getTightBounds()
-        for i in range(1, self.getNumPaths()):
-            v1x, v2x = self.getPath(i).getTightBounds()
-            v1 = Point3.Point3(min(v1[0], v1x[0]),
-                               min(v1[1], v1x[1]),
-                               min(v1[2], v1x[2]))
-            v2 = Point3.Point3(max(v2[0], v2x[0]),
-                               max(v2[1], v2x[1]),
-                               max(v2[2], v2x[2]))
-        
-        return v1, v2

+ 0 - 6
direct/src/extensions/OdeBody-extensions.py

@@ -1,6 +0,0 @@
-
-def getConvertedJoint(self, index):
-    """
-    Return a downcast joint on this body.
-    """
-    return self.getJoint(index).convert()

+ 0 - 44
direct/src/extensions/OdeGeom-extensions.py

@@ -1,44 +0,0 @@
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this geom in 
-    order to expose its specialized functions.
-    """
-    if self.getGeomClass() == OdeGeom.GCSphere:
-        return self.convertToSphere()
-    elif self.getGeomClass() == OdeGeom.GCBox:
-        return self.convertToBox()
-    elif self.getGeomClass() == OdeGeom.GCCappedCylinder:
-        return self.convertToCappedCylinder()
-    elif self.getGeomClass() == OdeGeom.GCPlane:
-        return self.convertToPlane()
-    elif self.getGeomClass() == OdeGeom.GCRay:
-        return self.convertToRay()
-    # elif self.getGeomClass() == OdeGeom.GCConvex:
-    #     return self.convertToConvex()
-    # elif self.getGeomClass() == OdeGeom.GCGeomTransform:
-    #     return self.convertToGeomTransform()
-    elif self.getGeomClass() == OdeGeom.GCTriMesh:
-        return self.convertToTriMesh()
-    # elif self.getGeomClass() == OdeGeom.GCHeightfield:
-    #     return self.convertToHeightfield()
-    elif self.getGeomClass() == OdeGeom.GCSimpleSpace:
-        return self.convertToSimpleSpace()
-    elif self.getGeomClass() == OdeGeom.GCHashSpace:
-        return self.convertToHashSpace()
-    elif self.getGeomClass() == OdeGeom.GCQuadTreeSpace:
-        return self.convertToQuadTreeSpace()
-
-def getConvertedSpace(self):
-    """
-    """
-    return self.getSpace().convert()
-
-def getAABounds(self):
-    """
-    A more Pythonic way of calling getAABB().
-    """
-    min = Point3()
-    max = Point3()
-    self.getAABB(min,max)
-    return min,max

+ 0 - 39
direct/src/extensions/OdeJoint-extensions.py

@@ -1,39 +0,0 @@
-def attach(self, body1, body2):
-    """
-    Attach two bodies together.
-    If either body is None, the other will be attached to the environment.
-    """
-    if body1 and body2:
-        self.attachBodies(body1, body2)
-    elif body1 and not body2:
-        self.attachBody(body1, 0)
-    elif not body1 and body2:
-        self.attachBody(body2, 1)
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this joint in 
-    order to expose its specialized functions.
-    """
-    if self.getJointType() == OdeJoint.JTBall:
-        return self.convertToBall()
-    elif self.getJointType() == OdeJoint.JTHinge:
-        return self.convertToHinge()
-    elif self.getJointType() == OdeJoint.JTSlider:
-        return self.convertToSlider()
-    elif self.getJointType() == OdeJoint.JTContact:
-        return self.convertToContact()
-    elif self.getJointType() == OdeJoint.JTUniversal:
-        return self.convertToUniversal()
-    elif self.getJointType() == OdeJoint.JTHinge2:
-        return self.convertToHinge2()
-    elif self.getJointType() == OdeJoint.JTFixed:
-        return self.convertToFixed()
-    elif self.getJointType() == OdeJoint.JTNull:
-        return self.convertToNull()
-    elif self.getJointType() == OdeJoint.JTAMotor:
-        return self.convertToAMotor()
-    elif self.getJointType() == OdeJoint.JTLMotor:
-        return self.convertToLMotor()
-    elif self.getJointType() == OdeJoint.JTPlane2d:
-        return self.convertToPlane2d()

+ 0 - 32
direct/src/extensions/OdeSpace-extensions.py

@@ -1,32 +0,0 @@
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this space in 
-    order to expose its specialized functions.
-    """
-    if self.getClass() == OdeGeom.GCSimpleSpace:
-        return self.convertToSimpleSpace()
-    elif self.getClass() == OdeGeom.GCHashSpace:
-        return self.convertToHashSpace()
-    elif self.getClass() == OdeGeom.GCQuadTreeSpace:
-        return self.convertToQuadTreeSpace()
-
-def getConvertedGeom(self, index):
-    """
-    Return a downcast geom on this body.
-    """
-    return self.getGeom(index).convert()
-
-def getConvertedSpace(self):
-    """
-    """
-    return self.getSpace().convert()
-
-def getAABounds(self):
-    """
-    A more Pythonic way of calling getAABB()
-    """
-    min = Point3()
-    max = Point3()
-    self.getAABB(min,max)
-    return min,max

+ 0 - 15
direct/src/extensions/Ramfile-extensions.py

@@ -1,15 +0,0 @@
-
-    """
-    Ramfile-extensions module: contains methods to extend functionality
-    of the Ramfile class
-    """
-
-    def readlines(self):
-        """Reads all the lines at once and returns a list."""
-        lines = []
-        line = self.readline()
-        while line:
-            lines.append(line)
-            line = self.readline()
-        return lines
-    

+ 0 - 15
direct/src/extensions/StreamReader-extensions.py

@@ -1,15 +0,0 @@
-
-    """
-    StreamReader-extensions module: contains methods to extend functionality
-    of the StreamReader class
-    """
-
-    def readlines(self):
-        """Reads all the lines at once and returns a list."""
-        lines = []
-        line = self.readline()
-        while line:
-            lines.append(line)
-            line = self.readline()
-        return lines
-    

+ 0 - 16
direct/src/extensions_native/EggGroupNode_extensions.py

@@ -1,16 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)        
-#del func
-#####################################################################
-    # For iterating over children
-def getChildren(self):
-        """Returns a Python list of the egg node's children."""
-        result = []
-        child = self.getFirstChild()
-        while (child != None):
-            result.append(child)
-            child = self.getNextChild()
-        return result
-    
-Dtool_funcToMethod(getChildren, EggGroupNode)        
-del getChildren

+ 0 - 13
direct/src/extensions_native/EggPrimitive_extensions.py

@@ -1,13 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)        
-#del func
-#####################################################################
-    # For iterating over vertices
-def getVertices(self):
-        """Returns a Python list of the egg primitive's vertices."""
-        result = []
-        for i in range(self.getNumVertices()):
-            result.append(self.getVertex(i))
-        return result
-Dtool_funcToMethod(getVertices, EggPrimitive)        
-del getVertices

+ 0 - 31
direct/src/extensions_native/NodePathCollection_extensions.py

@@ -1,31 +0,0 @@
-#####################################################################
-
-# For iterating over children
-def asList(self):
-    """Converts a NodePathCollection into a list"""
-    print "Warning: NodePathCollection.asList() is no longer needed and deprecated.  Iterate on the collection directly instead."
-    return list(self)
-        
-Dtool_funcToMethod(asList, NodePathCollection)        
-del asList
-#####################################################################3333      
-
-def getTightBounds(self):
-    from pandac.PandaModules import Point3
-    
-    if self.getNumPaths() == 0:
-        return (Point3(0), Point3(0))
-    v1, v2 = self.getPath(0).getTightBounds()
-    for i in range(1, self.getNumPaths()):
-        v1x, v2x = self.getPath(i).getTightBounds()
-        v1 = Point3(min(v1[0], v1x[0]),
-                    min(v1[1], v1x[1]),
-                    min(v1[2], v1x[2]))
-        v2 = Point3(max(v2[0], v2x[0]),
-                    max(v2[1], v2x[1]),
-                    max(v2[2], v2x[2]))
-    return v1, v2
-    
-Dtool_funcToMethod(getTightBounds, NodePathCollection)        
-del getTightBounds
-#####################################################################3333      

+ 0 - 9
direct/src/extensions_native/NodePath_extensions.py

@@ -154,15 +154,6 @@ def getAncestry(self):
 Dtool_funcToMethod(getAncestry, NodePath)
 del getAncestry
 #####################################################################
-def getTightBounds(self):
-        from pandac.PandaModules import Point3
-        v1 = Point3(0)
-        v2 = Point3(0)
-        self.calcTightBounds(v1, v2)
-        return v1, v2
-Dtool_funcToMethod(getTightBounds, NodePath)
-del getTightBounds
-#####################################################################
 
 def pPrintString(self, other = None):
         """

+ 0 - 18
direct/src/extensions_native/OdeBody_extensions.py

@@ -1,18 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)
-#del func
-#####################################################################
-
-"""
-OdeBody-extensions module: contains methods to extend functionality
-of the OdeBody classe
-"""
-
-def getConvertedJoint(self, index):
-    """
-    Return a downcast joint on this body.
-    """
-    return self.getJoint(index).convert()
-Dtool_funcToMethod(getConvertedJoint, OdeBody)
-del getConvertedJoint
-

+ 0 - 60
direct/src/extensions_native/OdeGeom_extensions.py

@@ -1,60 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)
-#del func
-#####################################################################
-
-"""
-OdeGeom-extensions module: contains methods to extend functionality
-of the OdeGeom class
-"""
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this geom in 
-    order to expose its specialized functions.
-    """
-    if self.getClass() == OdeGeom.GCSphere:
-        return self.convertToSphere()
-    elif self.getClass() == OdeGeom.GCBox:
-        return self.convertToBox()
-    elif self.getClass() == OdeGeom.GCCappedCylinder:
-        return self.convertToCappedCylinder()
-    elif self.getClass() == OdeGeom.GCPlane:
-        return self.convertToPlane()
-    elif self.getClass() == OdeGeom.GCRay:
-        return self.convertToRay()
-    # elif self.getClass() == OdeGeom.GCConvex:
-    #     return self.convertToConvex()
-    # elif self.getClass() == OdeGeom.GCGeomTransform:
-    #     return self.convertToGeomTransform()
-    elif self.getClass() == OdeGeom.GCTriMesh:
-        return self.convertToTriMesh()
-    # elif self.getClass() == OdeGeom.GCHeightfield:
-    #     return self.convertToHeightfield()
-    elif self.getClass() == OdeGeom.GCSimpleSpace:
-        return self.convertToSimpleSpace()
-    elif self.getClass() == OdeGeom.GCHashSpace:
-        return self.convertToHashSpace()
-    elif self.getClass() == OdeGeom.GCQuadTreeSpace:
-        return self.convertToQuadTreeSpace()
-Dtool_funcToMethod(convert, OdeGeom)
-del convert
-
-def getConvertedSpace(self):
-    """
-    """
-    return self.getSpace().convert()
-Dtool_funcToMethod(getConvertedSpace, OdeGeom)
-del getConvertedSpace
-
-def getAABounds(self):
-    """
-    A more Pythonic way of calling getAABB()
-    """
-    min = Point3()
-    max = Point3()
-    self.getAABB(min,max)
-    return min,max
-Dtool_funcToMethod(getAABounds, OdeGeom)
-del getAABounds
-

+ 0 - 54
direct/src/extensions_native/OdeJoint_extensions.py

@@ -1,54 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)
-#del func
-#####################################################################
-
-"""
-OdeJoint-extensions module: contains methods to extend functionality
-of the OdeJoint class
-"""
-
-def attach(self, body1, body2):
-    """
-    Attach two bodies together.
-    If either body is None, the other will be attached to the environment.
-    """
-    if body1 and body2:
-        self.attachBodies(body1, body2)
-    elif body1 and not body2:
-        self.attachBody(body1, 0)
-    elif not body1 and body2:
-        self.attachBody(body2, 1)
-Dtool_funcToMethod(attach, OdeJoint)
-del attach
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this joint in 
-    order to expose its specialized functions.
-    """
-    if self.getJointType() == OdeJoint.JTBall:
-        return self.convertToBall()
-    elif self.getJointType() == OdeJoint.JTHinge:
-        return self.convertToHinge()
-    elif self.getJointType() == OdeJoint.JTSlider:
-        return self.convertToSlider()
-    elif self.getJointType() == OdeJoint.JTContact:
-        return self.convertToContact()
-    elif self.getJointType() == OdeJoint.JTUniversal:
-        return self.convertToUniversal()
-    elif self.getJointType() == OdeJoint.JTHinge2:
-        return self.convertToHinge2()
-    elif self.getJointType() == OdeJoint.JTFixed:
-        return self.convertToFixed()
-    elif self.getJointType() == OdeJoint.JTNull:
-        return self.convertToNull()
-    elif self.getJointType() == OdeJoint.JTAMotor:
-        return self.convertToAMotor()
-    elif self.getJointType() == OdeJoint.JTLMotor:
-        return self.convertToLMotor()
-    elif self.getJointType() == OdeJoint.JTPlane2d:
-        return self.convertToPlane2d()
-Dtool_funcToMethod(convert, OdeJoint)
-del convert
-

+ 0 - 50
direct/src/extensions_native/OdeSpace_extensions.py

@@ -1,50 +0,0 @@
-####################################################################
-#Dtool_funcToMethod(func, class)
-#del func
-#####################################################################
-
-"""
-OdeSpace-extensions module: contains methods to extend functionality
-of the OdeSpace classe
-"""
-
-def convert(self):
-    """
-    Do a sort of pseudo-downcast on this space in 
-    order to expose its specialized functions.
-    """
-    if self.getClass() == OdeGeom.GCSimpleSpace:
-        return self.convertToSimpleSpace()
-    elif self.getClass() == OdeGeom.GCHashSpace:
-        return self.convertToHashSpace()
-    elif self.getClass() == OdeGeom.GCQuadTreeSpace:
-        return self.convertToQuadTreeSpace()
-Dtool_funcToMethod(convert, OdeSpace)
-del convert
-
-def getConvertedGeom(self, index):
-    """
-    Return a downcast geom on this space.
-    """
-    return self.getGeom(index).convert()
-Dtool_funcToMethod(getConvertedGeom, OdeSpace)
-del getConvertedGeom
-
-def getConvertedSpace(self):
-    """
-    """
-    return self.getSpace().convert()
-Dtool_funcToMethod(getConvertedSpace, OdeSpace)
-del getConvertedSpace
-
-def getAABounds(self):
-    """
-    A more Pythonic way of calling getAABB()
-    """
-    min = Point3()
-    max = Point3()
-    self.getAABB(min,max)
-    return min,max
-Dtool_funcToMethod(getAABounds, OdeSpace)
-del getAABounds
-

+ 0 - 16
direct/src/extensions_native/Ramfile_extensions.py

@@ -1,16 +0,0 @@
-"""
-Ramfile_extensions module: contains methods to extend functionality
-of the Ramfile class
-"""
-
-def readlines(self):
-    """Reads all the lines at once and returns a list."""
-    lines = []
-    line = self.readline()
-    while line:
-        lines.append(line)
-        line = self.readline()
-    return lines
-
-Dtool_funcToMethod(readlines, Ramfile)
-del readlines    

+ 0 - 16
direct/src/extensions_native/StreamReader_extensions.py

@@ -1,16 +0,0 @@
-"""
-StreamReader_extensions module: contains methods to extend functionality
-of the StreamReader class
-"""
-
-def readlines(self):
-    """Reads all the lines at once and returns a list."""
-    lines = []
-    line = self.readline()
-    while line:
-        lines.append(line)
-        line = self.readline()
-    return lines
-    
-Dtool_funcToMethod(readlines, StreamReader)        
-del readlines

+ 3 - 2
direct/src/interval/FunctionInterval.py

@@ -57,9 +57,10 @@ class FunctionInterval(Interval.Interval):
         self.function = function
             
         # Create a unique name for the interval if necessary
-        if (name == None):
+        if name is None:
             name = self.makeUniqueName(function)
-        assert isinstance(name, types.StringType)
+        assert isinstance(name, str)
+
         # Record any arguments
         self.extraArgs = extraArgs
         self.kw = kw

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

@@ -814,7 +814,7 @@ class Loader(DirectObject):
             result = []
             for soundPath in soundList:
                 # should return a valid sound obj even if musicMgr is invalid
-                sound = manager.getSound(soundPath)
+                sound = manager.getSound(soundPath, positional)
                 result.append(sound)
 
             if gotList:

+ 4 - 1
direct/src/showbase/Messenger.py

@@ -634,7 +634,10 @@ class Messenger:
             functionName = method.im_class.__name__ + '.' + \
                 method.im_func.__name__
         else:
-            functionName = method.__name__
+            if hasattr(method, "__name__"):
+                functionName = method.__name__
+            else:
+                return ""
         return functionName
 
     def __eventRepr(self, event):

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

@@ -60,9 +60,6 @@ import bisect
 __report_indent = 3
 
 from direct.directutil import Verify
-# Don't import libpandaexpressModules, which doesn't get built until
-# genPyCode.
-import direct.extensions_native.extension_native_helpers
 from panda3d.core import ConfigVariableBool
 
 ScalarTypes = (types.FloatType, types.IntType, types.LongType)
@@ -2462,7 +2459,8 @@ def _getDtoolSuperBase():
     from pandac.PandaModules import PandaNode
     dtoolSuperBase = PandaNode('').__class__.__bases__[0].__bases__[0].__bases__[0]
     assert repr(dtoolSuperBase) == "<type 'libdtoolconfig.DTOOL_SUPER_BASE111'>" \
-        or repr(dtoolSuperBase) == "<type 'libdtoolconfig.DTOOL_SUPPER_BASE111'>"
+        or repr(dtoolSuperBase) == "<type 'libdtoolconfig.DTOOL_SUPPER_BASE111'>" \
+        or repr(dtoolSuperBase) == "<type 'dtoolconfig.DTOOL_SUPER_BASE111'>"
     
 safeReprNotify = None
 

+ 28 - 18
dtool/src/interrogate/functionRemap.cxx

@@ -14,7 +14,7 @@
 
 #include "functionRemap.h"
 #include "typeManager.h"
-#include "interrogate.h" 
+#include "interrogate.h"
 #include "parameterRemap.h"
 #include "parameterRemapThis.h"
 #include "interfaceMaker.h"
@@ -324,7 +324,6 @@ make_wrapper_entry(FunctionIndex function_index) {
       _flags |= F_explicit_self;
     }
   }
-      
 
   if (!_void_return) {
     iwrapper._flags |= InterrogateFunctionWrapper::F_has_return;
@@ -340,15 +339,15 @@ make_wrapper_entry(FunctionIndex function_index) {
   if (_return_value_needs_management) {
     iwrapper._flags |= InterrogateFunctionWrapper::F_caller_manages;
     FunctionIndex destructor = _return_value_destructor;
-    
+
     if (destructor != 0) {
       iwrapper._return_value_destructor = destructor;
-      
+
     } else {
       // We don't need to report this warning, since the FFI code
       // understands that if the destructor function is zero, it
       // should use the regular class destructor.
-      
+
       //          nout << "Warning!  Destructor for " 
       //               << *_return_type->get_orig_type()
       //               << " is unavailable.\n"
@@ -397,8 +396,12 @@ get_call_str(const string &container, const vector_string &pexprs) const {
 
     // If this function is marked as having an extension function,
     // call that instead.
-    if (_extension && !container.empty()) {
-      call << "invoke_extension(" << container << ").";
+    if (_extension) {
+      if (!container.empty()) {
+        call << "invoke_extension(" << container << ").";
+      } else {
+        call << "Extension<" << _cpptype->get_local_name(&parser) << ">::";
+      }
 
       call << _cppfunc->get_local_name();
       call << "(";
@@ -413,7 +416,7 @@ get_call_str(const string &container, const vector_string &pexprs) const {
         // If we have a "this" parameter, the calling convention is also
         // a bit different.
         call << "(" << container << ")->" << _cppfunc->get_local_name();
-        
+
       } else {
         call << _cppfunc->get_local_name(&parser);
       }
@@ -465,7 +468,7 @@ get_parameter_expr(int n, const vector_string &pexprs) const {
 ////////////////////////////////////////////////////////////////////
 bool FunctionRemap::
 setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_maker) {
-  _function_signature = 
+  _function_signature =
     TypeManager::get_function_signature(_cppfunc, _num_default_parameters);
   _expression = ifunc._expression;
 
@@ -519,7 +522,7 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       _parameters.push_back(param);
       _first_true_parameter = 1;
     }
-      
+
     // Also check the name of the function.  If it's one of the
     // assignment-style operators, flag it as such.
     if (fname == "operator =" ||
@@ -611,7 +614,7 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     }
   }
 
-  if (_return_type == (ParameterRemap *)NULL || 
+  if (_return_type == (ParameterRemap *)NULL ||
       !_return_type->is_valid()) {
     // If our return type isn't something we can deal with, treat the
     // function as if it returns NULL.
@@ -621,25 +624,25 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     _return_type = interface_maker->remap_parameter(_cpptype, void_type);
     assert(_return_type != (ParameterRemap *)NULL);
   }
-  
+
   // Do we need to manage the return value?
-  _return_value_needs_management = 
+  _return_value_needs_management =
     _return_type->return_value_needs_management();
-  _return_value_destructor = 
+  _return_value_destructor =
     _return_type->get_return_value_destructor();
-  
+
   // Should we manage a reference count?
   CPPType *return_type = _return_type->get_new_type();
   return_type = TypeManager::resolve_type(return_type, _cppscope);
   CPPType *return_meat_type = TypeManager::unwrap_pointer(return_type);
-  
+
   if (manage_reference_counts &&
       TypeManager::is_reference_count_pointer(return_type) &&
       !TypeManager::has_protected_destructor(return_meat_type)) {
     // Yes!
     _manage_reference_count = true;
     _return_value_needs_management = true;
-    
+
     // This is problematic, because we might not have the class in
     // question fully defined here, particularly if the class is
     // defined in some other library.
@@ -709,11 +712,18 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
 
         _flags |= F_releasebuffer;
       }
+
+    } else if (fname == "compare_to" ) {
+      if (_has_this && _parameters.size() == 2 &&
+          TypeManager::is_integer(_return_type->get_new_type())) {
+        // It receives one parameter, and returns an integer.
+        _flags |= F_compare_to;
+      }
     }
 
   } else if (_type == T_constructor) {
     if (!_has_this && _parameters.size() == 1) {
-      if (TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) == 
+      if (TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
           TypeManager::unwrap(_return_type->get_orig_type())) {
         // If this is the only parameter, and it's the same as the
         // "this" type, this is a copy constructor.

+ 2 - 1
dtool/src/interrogate/functionRemap.h

@@ -90,6 +90,7 @@ public:
     F_iter             = 0x0100,
     F_getbuffer        = 0x0200,
     F_releasebuffer    = 0x0400,
+    F_compare_to       = 0x0800,
   };
 
   typedef vector<Parameter> Parameters;
@@ -113,7 +114,7 @@ public:
   string _reported_name;
   string _wrapper_name;
   FunctionWrapperIndex _wrapper_index;
-  
+
   bool _return_value_needs_management;
   FunctionIndex _return_value_destructor;
   bool _manage_reference_count;

File diff suppressed because it is too large
+ 178 - 137
dtool/src/interrogate/interfaceMakerPythonNative.cxx


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

@@ -1679,6 +1679,10 @@ get_function(CPPInstance *function, string description,
     InterrogateFunction &ifunction =
       InterrogateDatabase::get_ptr()->update_function(index);
 
+    // Not 100% sure why, but there's a case where this happens,
+    // in a case where a typedef shadowed an actual type. ~rdb
+    nassertr(&ifunction != NULL, 0);
+
     ifunction._flags |= flags;
 
     // Also, make sure this particular signature is defined.

+ 1 - 1
dtool/src/interrogate/interrogate_module.cxx

@@ -112,7 +112,7 @@ int write_python_table_native(ostream &out) {
   pset<std::string >::iterator ii;
   for(ii = libraries.begin(); ii != libraries.end(); ii++) {
     printf("Referencing Library %s\n", (*ii).c_str());
-    out << "extern LibraryDef " << *ii << "_moddef;\n";
+    out << "IMPORT_THIS LibraryDef " << *ii << "_moddef;\n";
   }
 
   out << "\n"

+ 3 - 9
dtool/src/interrogatedb/extension.h

@@ -17,10 +17,7 @@
 
 #include "dtoolbase.h"
 
-struct _object;
-typedef struct _object PyObject;
-
-////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
 //       Class : ExtensionBase
 // Description : This is where all extensions should derive from.
 //               It defines the _self and _this members that can
@@ -30,7 +27,6 @@ template<class T>
 class EXPCL_DTOOLCONFIG ExtensionBase {
 public:
   T * _this;
-  PyObject * _self;
 };
 
 ////////////////////////////////////////////////////////////////////
@@ -52,10 +48,9 @@ class EXPCL_DTOOLCONFIG Extension : public ExtensionBase<T> {
 ////////////////////////////////////////////////////////////////////
 template<class T>
 inline Extension<T>
-invoke_extension(T *ptr, PyObject *self = NULL) {
+invoke_extension(T *ptr) {
   Extension<T> ext;
   ext._this = ptr;
-  ext._self = self;
   return ext;
 }
 
@@ -65,10 +60,9 @@ invoke_extension(T *ptr, PyObject *self = NULL) {
 ////////////////////////////////////////////////////////////////////
 template<class T>
 inline const Extension<T>
-invoke_extension(const T *ptr, PyObject *self = NULL) {
+invoke_extension(const T *ptr) {
   Extension<T> ext;
   ext._this = (T *) ptr;
-  ext._self = self;
   return ext;
 }
 

+ 3 - 3
dtool/src/interrogatedb/py_panda.cxx

@@ -49,7 +49,7 @@ bool DtoolCanThisBeAPandaInstance(PyObject *self) {
 ////////////////////////////////////////////////////////////////////////
 void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer) {
   if (DtoolCanThisBeAPandaInstance(self)) {
-    *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self,classdef);
+    *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, classdef);
   } else {
     *answer = NULL;
   }
@@ -298,7 +298,7 @@ void *DTOOL_Call_GetPointerThis(PyObject *self) {
 // this function relies on the behavior of typed objects in the panda system.
 //
 ////////////////////////////////////////////////////////////////////////
-PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType) {     
+PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType) {
   if (local_this_in == NULL) {
     // Let's not be stupid..
     PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
@@ -339,7 +339,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
   // if we get this far .. just wrap the thing in the known type ??
   //    better than aborting...I guess....
   /////////////////////////////////////////////////////
-  Dtool_PyInstDef * self = (Dtool_PyInstDef *) known_class_type.As_PyTypeObject().tp_new(&known_class_type.As_PyTypeObject(), NULL, NULL);
+  Dtool_PyInstDef *self = (Dtool_PyInstDef *) known_class_type.As_PyTypeObject().tp_new(&known_class_type.As_PyTypeObject(), NULL, NULL);
   if (self != NULL) {
     self->_ptr_to_object = local_this_in;
     self->_memory_rules = memory_rules;

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

@@ -25,4 +25,7 @@ class PyThreadState;
 typedef int Py_ssize_t;
 struct Py_buffer;
 
+// This file defines PY_VERSION_HEX, which is used in some places.
+#include "patchlevel.h"
+
 #endif  // PYTHON_H

+ 1 - 0
dtool/src/prc/streamReader.h

@@ -70,6 +70,7 @@ PUBLISHED:
   BLOCKING size_t extract_bytes(unsigned char *into, size_t size);
 
   BLOCKING string readline();
+  EXTENSION(BLOCKING PyObject *readlines());
 
 private:
   istream *_in;

BIN
makepanda/Panda3D-tpl.dmg


+ 8 - 10
makepanda/installpanda.py

@@ -125,7 +125,6 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"):
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/bin")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/include")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/panda3d")
-    oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/panda3d/direct")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime-info")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/mime/packages")
     oscmd("mkdir -m 0755 -p "+destdir+prefix+"/share/application-registry")
@@ -137,7 +136,6 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"):
         oscmd("mkdir -m 0755 -p "+destdir+"/usr/local/libdata/ldconfig")
     else:
         oscmd("mkdir -m 0755 -p "+destdir+"/etc/ld.so.conf.d")
-    WriteFile(destdir+prefix+"/share/panda3d/direct/__init__.py", "")
     Configrc = ReadFile(outputdir+"/etc/Config.prc")
     Configrc = Configrc.replace("model-path    $THIS_PRC_DIR/..", "model-path    "+prefix+"/share/panda3d")
     if (sys.platform.startswith("freebsd")):
@@ -147,13 +145,13 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"):
         WriteFile(destdir+"/etc/Config.prc", Configrc)
         oscmd("cp "+outputdir+"/etc/Confauto.prc    "+destdir+"/etc/Confauto.prc")
     oscmd("cp -R "+outputdir+"/include          "+destdir+prefix+"/include/panda3d")
-    oscmd("cp -R direct/src/*                   "+destdir+prefix+"/share/panda3d/direct")
-    oscmd("cp -R "+outputdir+"/pandac           "+destdir+prefix+"/share/panda3d/pandac")
-    oscmd("cp -R "+outputdir+"/models           "+destdir+prefix+"/share/panda3d/models")
-    oscmd("cp direct/src/ffi/panda3d.py         "+destdir+prefix+"/share/panda3d/panda3d.py")
-    if os.path.isdir("samples"):             oscmd("cp -R samples               "+destdir+prefix+"/share/panda3d/samples")
-    if os.path.isdir(outputdir+"/Pmw"):      oscmd("cp -R "+outputdir+"/Pmw     "+destdir+prefix+"/share/panda3d/Pmw")
-    if os.path.isdir(outputdir+"/plugins"):  oscmd("cp -R "+outputdir+"/plugins "+destdir+prefix+"/share/panda3d/plugins")
+    oscmd("cp -R "+outputdir+"/direct           "+destdir+prefix+"/share/panda3d/")
+    oscmd("cp -R "+outputdir+"/pandac           "+destdir+prefix+"/share/panda3d/")
+    oscmd("cp -R "+outputdir+"/panda3d          "+destdir+PPATH+"/")
+    oscmd("cp -R "+outputdir+"/models           "+destdir+prefix+"/share/panda3d/")
+    if os.path.isdir("samples"):             oscmd("cp -R samples               "+destdir+prefix+"/share/panda3d/")
+    if os.path.isdir(outputdir+"/Pmw"):      oscmd("cp -R "+outputdir+"/Pmw     "+destdir+prefix+"/share/panda3d/")
+    if os.path.isdir(outputdir+"/plugins"):  oscmd("cp -R "+outputdir+"/plugins "+destdir+prefix+"/share/panda3d/")
     WriteMimeFile(destdir+prefix+"/share/mime-info/panda3d.mime", MIME_INFO)
     WriteKeysFile(destdir+prefix+"/share/mime-info/panda3d.keys", MIME_INFO)
     WriteMimeXMLFile(destdir+prefix+"/share/mime/packages/panda3d.xml", MIME_INFO)
@@ -169,7 +167,7 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built"):
     else:
         oscmd("echo '"+libdir+"/panda3d'>    "+destdir+"/etc/ld.so.conf.d/panda3d.conf")
         oscmd("chmod +x "+destdir+"/etc/ld.so.conf.d/panda3d.conf")
-    oscmd("ln -s "+PEXEC+"                      "+destdir+prefix+"/bin/ppython")
+    oscmd("ln -f -s "+PEXEC+"                   "+destdir+prefix+"/bin/ppython")
     oscmd("cp "+outputdir+"/bin/*               "+destdir+prefix+"/bin/")
     for base in os.listdir(outputdir+"/lib"):
         if (not base.endswith(".a")) or base == "libp3pystub.a":

File diff suppressed because it is too large
+ 314 - 188
makepanda/makepanda.py


+ 43 - 23
makepanda/makepandacore.py

@@ -9,13 +9,15 @@
 ##
 ########################################################################
 
-import sys,os,time,stat,string,re,getopt,fnmatch,threading,signal,shutil,platform,glob,getpass,signal,thread
+import sys,os,time,stat,string,re,getopt,fnmatch,threading,signal,shutil,platform,glob,getpass,signal
 from distutils import sysconfig
 
 if sys.version_info >= (3, 0):
     import pickle
+    import _thread as thread
 else:
     import cPickle as pickle
+    import thread
 
 SUFFIX_INC = [".cxx",".c",".h",".I",".yxx",".lxx",".mm",".rc",".r"]
 SUFFIX_DLL = [".dll",".dlo",".dle",".dli",".dlm",".mll",".exe",".pyd",".ocx"]
@@ -694,11 +696,16 @@ def CxxGetIncludes(path):
     except:
         exit("Cannot open source file \""+path+"\" for reading.")
     include = []
-    for line in sfile:
-        match = CxxIncludeRegex.match(line,0)
-        if (match):
-            incname = match.group(1)
-            include.append(incname)
+    try:
+        for line in sfile:
+            match = CxxIncludeRegex.match(line,0)
+            if (match):
+                incname = match.group(1)
+                include.append(incname)
+    except:
+        print("Failed to determine dependencies of \""+path+"\".")
+        raise
+
     sfile.close()
     CXXINCLUDECACHE[path] = [date, include]
     return include
@@ -1062,6 +1069,8 @@ def MakeBuildTree():
     MakeDirectory(OUTPUTDIR + "/models/gui")
     MakeDirectory(OUTPUTDIR + "/pandac")
     MakeDirectory(OUTPUTDIR + "/pandac/input")
+    MakeDirectory(OUTPUTDIR + "/panda3d")
+    CreateFile(OUTPUTDIR + "/panda3d/__init__.py")
 
     if GetTarget() == 'android':
         MakeDirectory(OUTPUTDIR + "/libs")
@@ -1549,9 +1558,14 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             if SystemLibraryExists(libname):
                 LibName(target_pkg, "-l" + libname)
             else:
-                have_pkg = False
-                if VERBOSE:
-                    print(GetColor("cyan") + "Couldn't find library lib" + libname + GetColor())
+                # Try searching in the package's LibDirectories.
+                lpath = [dir for ppkg, dir in LIBDIRECTORIES if pkg == ppkg]
+                if LibraryExists(libname, lpath):
+                    LibName(target_pkg, "-l" + libname)
+                else:
+                    have_pkg = False
+                    if VERBOSE:
+                        print(GetColor("cyan") + "Couldn't find library lib" + libname + GetColor())
 
         for i in incs:
             incdir = None
@@ -1563,17 +1577,18 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
             elif (os.path.isdir(sysroot_usr + "/PCBSD") and len(glob.glob(sysroot_usr + "/PCBSD/local/include/" + i)) > 0):
                 incdir = sorted(glob.glob(sysroot_usr + "/PCBSD/local/include/" + i))[-1]
             else:
-                have_pkg = False
                 # Try searching in the package's IncDirectories.
                 for ppkg, pdir in INCDIRECTORIES:
-                    if (pkg == ppkg and len(glob.glob(os.path.join(pdir, i))) > 0):
+                    if pkg == ppkg and len(glob.glob(os.path.join(pdir, i))) > 0:
                         incdir = sorted(glob.glob(os.path.join(pdir, i)))[-1]
-                        have_pkg = True
-                if (incdir == None and VERBOSE and i.endswith(".h")):
-                    print(GetColor("cyan") + "Couldn't find header file " + i + GetColor())
+
+                if incdir is None and i.endswith(".h"):
+                    have_pkg = False
+                    if VERBOSE:
+                        print(GetColor("cyan") + "Couldn't find header file " + i + GetColor())
 
             # Note: It's possible to specify a file instead of a dir, for the sake of checking if it exists.
-            if (incdir != None and os.path.isdir(incdir)):
+            if incdir is not None and os.path.isdir(incdir):
                 IncDirectory(target_pkg, incdir)
 
         if (not have_pkg):
@@ -2380,7 +2395,7 @@ def CopyPythonTree(dstdir, srcdir, lib2to3_fixers=[]):
         dstpth = os.path.join(dstdir, entry)
         if (os.path.isfile(srcpth)):
             base, ext = os.path.splitext(entry)
-            if (entry != ".cvsignore" and ext not in SUFFIX_INC):
+            if (entry != ".cvsignore" and ext not in SUFFIX_INC + ['.pyc', '.pyo']):
                 if (NeedsBuild([dstpth], [srcpth])):
                     WriteBinaryFile(dstpth, ReadBinaryFile(srcpth))
 
@@ -2412,10 +2427,10 @@ def ParsePandaVersion(fn):
         f = open(fn, "r")
         pattern = re.compile('^[ \t]*[#][ \t]*define[ \t]+PANDA_VERSION[ \t]+([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)')
         for line in f:
-            match = pattern.match(line,0)
+            match = pattern.match(line, 0)
             if (match):
                 f.close()
-                return match.group(1)+"."+match.group(2)+"."+match.group(3)
+                return match.group(1) + "." + match.group(2) + "." + match.group(3)
         f.close()
     except: pass
     return "0.0.0"
@@ -2428,7 +2443,7 @@ def ParsePluginVersion(fn):
             match = pattern.match(line,0)
             if (match):
                 f.close()
-                return match.group(1)+"."+match.group(2)+"."+match.group(3)
+                return match.group(1) + "." + match.group(2) + "." + match.group(3)
         f.close()
     except: pass
     return "0.0.0"
@@ -2522,7 +2537,7 @@ def WriteResourceFile(basename, **kwargs):
 ##
 ########################################################################
 
-ORIG_EXT={}
+ORIG_EXT = {}
 
 def GetOrigExt(x):
     return ORIG_EXT[x]
@@ -2556,7 +2571,7 @@ def CalcLocation(fn, ipath):
         if (fn.endswith(".res")):   return OUTPUTDIR+"/tmp/"+fn
         if (fn.endswith(".tlb")):   return OUTPUTDIR+"/tmp/"+fn
         if (fn.endswith(".dll")):   return OUTPUTDIR+"/bin/"+fn[:-4]+dllext+".dll"
-        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/bin/"+fn[:-4]+dllext+".pyd"
+        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/panda3d/"+fn[:-4]+dllext+".pyd"
         if (fn.endswith(".ocx")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".ocx"
         if (fn.endswith(".mll")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".mll"
         if (fn.endswith(".dlo")):   return OUTPUTDIR+"/plugins/"+fn[:-4]+dllext+".dlo"
@@ -2572,7 +2587,7 @@ def CalcLocation(fn, ipath):
         if (fn.endswith(".plist")): return CxxFindSource(fn, ipath)
         if (fn.endswith(".obj")):   return OUTPUTDIR+"/tmp/"+fn[:-4]+".o"
         if (fn.endswith(".dll")):   return OUTPUTDIR+"/lib/"+fn[:-4]+".dylib"
-        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/lib/"+fn[:-4]+".so"
+        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/panda3d/"+fn[:-4]+".so"
         if (fn.endswith(".mll")):   return OUTPUTDIR+"/plugins/"+fn
         if (fn.endswith(".exe")):   return OUTPUTDIR+"/bin/"+fn[:-4]
         if (fn.endswith(".lib")):   return OUTPUTDIR+"/lib/"+fn[:-4]+".a"
@@ -2593,7 +2608,7 @@ def CalcLocation(fn, ipath):
     else:
         if (fn.endswith(".obj")):   return OUTPUTDIR+"/tmp/"+fn[:-4]+".o"
         if (fn.endswith(".dll")):   return OUTPUTDIR+"/lib/"+fn[:-4]+".so"
-        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/lib/"+fn[:-4]+".so"
+        if (fn.endswith(".pyd")):   return OUTPUTDIR+"/panda3d/"+fn[:-4]+".so"
         if (fn.endswith(".mll")):   return OUTPUTDIR+"/plugins/"+fn
         if (fn.endswith(".plugin")):return OUTPUTDIR+"/plugins/"+fn[:-7]+dllext+".so"
         if (fn.endswith(".exe")):   return OUTPUTDIR+"/bin/"+fn[:-4]
@@ -2669,6 +2684,11 @@ def TargetAdd(target, dummy=0, opts=0, input=0, dep=0, ipath=0, winrc=0):
     if (ipath == 0): ipath = []
     if (type(input) == str): input = [input]
     if (type(dep) == str): dep = [dep]
+
+    if os.path.splitext(target)[1] == '.pyd' and PkgSkip("PYTHON"):
+        # It makes no sense to build Python modules with python disabled.
+        return
+
     full = FindLocation(target, [OUTPUTDIR + "/include"])
 
     if (full not in TARGET_TABLE):

+ 14 - 15
panda/src/bullet/bulletContactResult.I

@@ -14,41 +14,40 @@
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_node0
+//     Function: BulletContact::get_node0
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *BulletContact::
 get_node0() const {
 
-  return _obj0 ? (PandaNode *)_obj0->getUserPointer() : NULL;
+  return _node0;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_node1
+//     Function: BulletContact::get_node1
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
 INLINE PandaNode *BulletContact::
 get_node1() const {
 
-  return _obj1 ? (PandaNode *)_obj1->getUserPointer() : NULL;
+  return _node1;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_manifold_point
+//     Function: BulletContact::get_manifold_point
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE const BulletManifoldPoint *BulletContact::
-get_manifold_point() const {
+INLINE BulletManifoldPoint &BulletContact::
+get_manifold_point() {
 
-  btManifoldPoint &mp = const_cast<btManifoldPoint &>(_mp);
-  return new BulletManifoldPoint(mp);
+  return _mp;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_idx0
+//     Function: BulletContact::get_idx0
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
@@ -59,7 +58,7 @@ get_idx0() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_idx1
+//     Function: BulletContact::get_idx1
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
@@ -70,7 +69,7 @@ get_idx1() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_part_id0
+//     Function: BulletContact::get_part_id0
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
@@ -81,7 +80,7 @@ get_part_id0() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletContactResult::get_part_id1
+//     Function: BulletContact::get_part_id1
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
@@ -107,8 +106,8 @@ get_num_contacts() const {
 //       Access: Published
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE const BulletContact &BulletContactResult::
-get_contact(int idx) const {
+INLINE BulletContact &BulletContactResult::
+get_contact(int idx) {
 
   nassertr(idx >= 0 && idx < (int)_contacts.size(), _empty);
   return _contacts[idx];

+ 75 - 6
panda/src/bullet/bulletContactResult.cxx

@@ -14,8 +14,37 @@
 
 #include "bulletContactResult.h"
 
+btManifoldPoint BulletContact::_empty;
 BulletContact BulletContactResult::_empty;
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletContact::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+BulletContact::
+BulletContact() : _mp(_empty) {
+
+  _node0 = NULL;
+  _node1 = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletContact::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+BulletContact::
+BulletContact(const BulletContact &other) : _mp(other._mp) {
+
+  _node0 = other._node0;
+  _node1 = other._node1;
+  _part_id0 = other._part_id0;
+  _part_id1 = other._part_id1;
+  _idx0 = other._idx0;
+  _idx1 = other._idx1;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletContactResult::Constructor
 //       Access: Protected
@@ -24,9 +53,46 @@ BulletContact BulletContactResult::_empty;
 BulletContactResult::
 BulletContactResult() : btCollisionWorld::ContactResultCallback() {
 
+#if BT_BULLET_VERSION >= 281
+  _filter_cb = NULL;
+  _filter_proxy = NULL;
+  _filter_set = false;
+#endif
 }
 
 #if BT_BULLET_VERSION >= 281
+////////////////////////////////////////////////////////////////////
+//     Function: BulletContactResult::use_filter
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void BulletContactResult::
+use_filter(btOverlapFilterCallback *cb, btBroadphaseProxy *proxy) {
+
+  nassertv(cb);
+  nassertv(proxy);
+
+  _filter_cb = cb;
+  _filter_proxy = proxy;
+  _filter_set = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletContactResult::needsCollision
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool BulletContactResult::
+needsCollision(btBroadphaseProxy *proxy0) const {
+
+  if (_filter_set) {
+    return _filter_cb->needBroadphaseCollision(proxy0, _filter_proxy);
+  }
+  else {
+    return true;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletContactResult::addSingleResult
 //       Access: Published
@@ -37,11 +103,14 @@ addSingleResult(btManifoldPoint &mp,
                 const btCollisionObjectWrapper *wrap0, int part_id0, int idx0,
                 const btCollisionObjectWrapper *wrap1, int part_id1, int idx1) {
 
+  const btCollisionObject *obj0 = wrap0->getCollisionObject();
+  const btCollisionObject *obj1 = wrap1->getCollisionObject();
+
   BulletContact contact;
 
-  contact._mp = mp;
-  contact._obj0 = wrap0->getCollisionObject();
-  contact._obj1 = wrap1->getCollisionObject();
+  contact._mp = BulletManifoldPoint(mp);
+  contact._node0 = obj0 ? (PandaNode *)obj0->getUserPointer() : NULL;
+  contact._node1 = obj1 ? (PandaNode *)obj1->getUserPointer() : NULL;
   contact._part_id0 = part_id0;
   contact._part_id1 = part_id1;
   contact._idx0 = idx0;
@@ -64,9 +133,9 @@ addSingleResult(btManifoldPoint &mp,
 
   BulletContact contact;
 
-  contact._mp = mp;
-  contact._obj0 = obj0;
-  contact._obj1 = obj1;
+  contact._mp = BulletManifoldPoint(mp);
+  contact._node0 = obj0 ? (PandaNode *)obj0->getUserPointer() : NULL;
+  contact._node1 = obj1 ? (PandaNode *)obj1->getUserPointer() : NULL;
   contact._part_id0 = part_id0;
   contact._part_id1 = part_id1;
   contact._idx0 = idx0;

+ 25 - 5
panda/src/bullet/bulletContactResult.h

@@ -28,8 +28,12 @@
 ////////////////////////////////////////////////////////////////////
 struct EXPCL_PANDABULLET BulletContact {
 
+public:
+  BulletContact();
+  BulletContact(const BulletContact &other);
+
 PUBLISHED:
-  INLINE const BulletManifoldPoint *get_manifold_point() const;
+  INLINE BulletManifoldPoint &get_manifold_point();
   INLINE PandaNode *get_node0() const;
   INLINE PandaNode *get_node1() const;
   INLINE const int get_idx0() const;
@@ -38,9 +42,13 @@ PUBLISHED:
   INLINE const int get_part_id1() const;
 
 private:
-  btManifoldPoint _mp;
-  const btCollisionObject *_obj0;
-  const btCollisionObject *_obj1;
+  static btManifoldPoint _empty;
+
+  BulletManifoldPoint _mp;
+
+  PT(PandaNode) _node0;
+  PT(PandaNode) _node1;
+
   int _part_id0;
   int _part_id1;
   int _idx0;
@@ -57,11 +65,13 @@ struct EXPCL_PANDABULLET BulletContactResult : public btCollisionWorld::ContactR
 
 PUBLISHED:
   INLINE int get_num_contacts() const;
-  INLINE const BulletContact &get_contact(int idx) const;
+  INLINE BulletContact &get_contact(int idx);
   MAKE_SEQ(get_contacts, get_num_contacts, get_contact);
 
 public:
 #if BT_BULLET_VERSION >= 281
+  virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
   virtual btScalar addSingleResult(btManifoldPoint &mp,
       const btCollisionObjectWrapper *wrap0, int part_id0, int idx0, 
       const btCollisionObjectWrapper *wrap1, int part_id1, int idx1); 
@@ -74,11 +84,21 @@ public:
 protected:
   BulletContactResult();
 
+#if BT_BULLET_VERSION >= 281
+  void use_filter(btOverlapFilterCallback *cb, btBroadphaseProxy *proxy);
+#endif
+
 private:
   static BulletContact _empty;
 
   btAlignedObjectArray<BulletContact> _contacts;
 
+#if BT_BULLET_VERSION >= 281
+  bool _filter_set;
+  btOverlapFilterCallback *_filter_cb;
+  btBroadphaseProxy *_filter_proxy;
+#endif
+
   friend class BulletWorld;
 };
 

+ 19 - 9
panda/src/bullet/bulletHelper.cxx

@@ -220,9 +220,11 @@ make_geom(BulletSoftBodyNode *node, const GeomVertexFormat *format, bool two_sid
 
   if (two_sided) {
     for (int j=0; j<nodes.size(); ++j) {
-      btVector3 &v = nodes[j].m_x;
+      btVector3 v = nodes[j].m_x;
       btVector3 &n = nodes[j].m_n;
 
+      v = trans.invXform(v);
+
       vwriter.add_data3((PN_stdfloat)v.getX(), (PN_stdfloat)v.getY(), (PN_stdfloat)v.getZ());
       nwriter.add_data3((PN_stdfloat)n.getX(), (PN_stdfloat)n.getY(), (PN_stdfloat)n.getZ());
       fwriter.add_data1i(1);
@@ -231,23 +233,29 @@ make_geom(BulletSoftBodyNode *node, const GeomVertexFormat *format, bool two_sid
 
   // Indices
   btSoftBody::Node *node0 = &nodes[0];
+  int i0, i1, i2;
 
   if (use_faces) {
+
     btSoftBody::tFaceArray &faces(body->m_faces);
 
     prim = new GeomTriangles(Geom::UH_stream);
     prim->set_shade_model(Geom::SM_uniform);
 
     for (int j=0; j<faces.size(); ++j) {
-      prim->add_vertices(int(faces[j].m_n[0] - node0),
-                         int(faces[j].m_n[1] - node0),
-                         int(faces[j].m_n[2] - node0));
+      i0 = int(faces[j].m_n[0] - node0);
+      i1 = int(faces[j].m_n[1] - node0);
+      i2 = int(faces[j].m_n[2] - node0);
+
+      prim->add_vertices(i0, i1, i2);
       prim->close_primitive();
 
       if (two_sided) {
-        prim->add_vertices(nodes.size() + int(faces[j].m_n[0] - node0),
-                           nodes.size() + int(faces[j].m_n[2] - node0),
-                           nodes.size() + int(faces[j].m_n[1] - node0));
+        i0 = nodes.size() + int(faces[j].m_n[0] - node0);
+        i1 = nodes.size() + int(faces[j].m_n[2] - node0);
+        i2 = nodes.size() + int(faces[j].m_n[1] - node0);
+
+        prim->add_vertices(i0, i1, i2);
         prim->close_primitive();
       }
     }
@@ -259,8 +267,10 @@ make_geom(BulletSoftBodyNode *node, const GeomVertexFormat *format, bool two_sid
     prim->set_shade_model(Geom::SM_uniform);
 
     for (int j=0; j<links.size(); ++j) {
-      prim->add_vertices(int(links[j].m_n[0] - node0),
-                         int(links[j].m_n[1] - node0));
+      i0 = int(links[j].m_n[0] - node0);
+      i1 = int(links[j].m_n[1] - node0);
+
+      prim->add_vertices(i0, i1);
       prim->close_primitive();
     }
   }

+ 22 - 0
panda/src/bullet/bulletManifoldPoint.cxx

@@ -25,6 +25,28 @@ BulletManifoldPoint(btManifoldPoint &pt)
 
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletManifoldPoint::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+BulletManifoldPoint::
+BulletManifoldPoint(const BulletManifoldPoint &other) 
+ : _pt(other._pt) {
+
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletManifoldPoint::Copy Assignment
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+BulletManifoldPoint& BulletManifoldPoint::
+operator=(const BulletManifoldPoint& other) {
+ 
+  return *this;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletManifoldPoint::get_lift_time
 //       Access: Published

+ 3 - 0
panda/src/bullet/bulletManifoldPoint.h

@@ -73,6 +73,9 @@ PUBLISHED:
 public:
   BulletManifoldPoint(btManifoldPoint &pt);
 
+  BulletManifoldPoint(const BulletManifoldPoint &other);
+  BulletManifoldPoint& operator=(const BulletManifoldPoint& other);
+
 private:
   btManifoldPoint &_pt;
 };

+ 1 - 1
panda/src/bullet/bulletSoftBodyConfig.h

@@ -29,7 +29,7 @@ PUBLISHED:
   INLINE ~BulletSoftBodyConfig();
 
   enum CollisionFlag {
-    CF_rigid__vs_soft_mask   = 0x000f, // RVSmask: Rigid versus soft mask
+    CF_rigid_vs_soft_mask    = 0x000f, // RVSmask: Rigid versus soft mask
     CF_sdf_rigid_soft        = 0x0001, // SDF_RS:  SDF based rigid vs soft
     CF_cluster_rigid_soft    = 0x0002, // CL_RS:   Cluster vs convex rigid vs soft
     CF_soft_vs_soft_mask     = 0x0030, // SVSmask: Soft versus soft mask

+ 52 - 17
panda/src/bullet/bulletSoftBodyNode.cxx

@@ -194,22 +194,35 @@ transform_changed() {
   LMatrix4 m_ts = ts->get_mat();
 
   if (!m_sync.almost_equal(m_ts)) {
-    _sync = ts;
 
+    // New transform for the center
     btTransform trans = TransformState_to_btTrans(ts);
 
-    trans *= _soft->m_initialWorldTransform.inverse();
+    // Offset between current approx center and current initial transform
+    btVector3 pos = LVecBase3_to_btVector3(this->get_aabb().get_approx_center());
+    btVector3 origin = _soft->m_initialWorldTransform.getOrigin();
+    btVector3 offset = pos - origin;
+
+    // Subtract offset to get new transform for the body
+    trans.setOrigin(trans.getOrigin() - offset);
+
+    // Now apply the new transform
+    _soft->transform(_soft->m_initialWorldTransform.inverse());
     _soft->transform(trans);
 
     if (ts->has_scale()) {
-      LVecBase3 scale = ts->get_scale();
-      if (!scale.almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
-        for (int i=0; i<get_num_shapes(); i++) {
-          PT(BulletShape) shape = _shapes[i];
-          shape->set_local_scale(scale);
-        }
-      }
+      btVector3 current_scale = LVecBase3_to_btVector3(_sync->get_scale());
+      btVector3 new_scale = LVecBase3_to_btVector3(ts->get_scale());
+
+      current_scale.setX(1.0 / current_scale.getX());
+      current_scale.setY(1.0 / current_scale.getY());
+      current_scale.setZ(1.0 / current_scale.getZ());
+
+      _soft->scale(current_scale);
+      _soft->scale(new_scale);
     }
+
+    _sync = ts;
   }
 }
 
@@ -221,7 +234,7 @@ transform_changed() {
 void BulletSoftBodyNode::
 sync_p2b() {
 
-  transform_changed();
+  //transform_changed(); Disabled for now...
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -280,22 +293,21 @@ sync_b2p() {
     }
   }
 
-  // It is ok to pass the address of a temporary object here, because
-  // set_bounds does not store the pointer - it makes a copy using
-  // volume->make_copy().
-  BoundingBox bb = this->get_aabb();
-  LVecBase3 pos = bb.get_approx_center();
+  // Update the synchronized transform with the current
+  // approximate center of the soft body
+  LVecBase3 pos = this->get_aabb().get_approx_center();
+  CPT(TransformState) ts = TransformState::make_pos(pos);
 
   NodePath np = NodePath::any_path((PandaNode *)this);
   LVecBase3 scale = np.get_net_transform()->get_scale();
-
-  CPT(TransformState) ts = TransformState::make_pos(pos);
   ts = ts->set_scale(scale);
 
   _sync = ts;
   _sync_disable = true;
   np.set_transform(NodePath(), ts);
   _sync_disable = false;
+/*
+*/
 
   Thread *current_thread = Thread::get_current_thread();
   this->r_mark_geom_bounds_stale(current_thread);
@@ -1135,3 +1147,26 @@ append_angular_joint(BulletBodyNode *body, const LVector3 &axis, PN_stdfloat erp
   _soft->appendAngularJoint(as, ptr);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSoftBodyNode::set_wind_velocity
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BulletSoftBodyNode::
+set_wind_velocity(const LVector3 &velocity) {
+
+  nassertv(!velocity.is_nan());
+  _soft->setWindVelocity(LVecBase3_to_btVector3(velocity));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BulletSoftBodyNode::get_wind_velocity
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+LVector3 BulletSoftBodyNode::
+get_wind_velocity() const {
+
+  return btVector3_to_LVector3(_soft->getWindVelocity());
+}
+

+ 3 - 0
panda/src/bullet/bulletSoftBodyNode.h

@@ -96,6 +96,9 @@ PUBLISHED:
   void add_velocity(const LVector3 &velocity);
   void add_velocity(const LVector3 &velocity, int node);
 
+  void set_wind_velocity(const LVector3 &velocity);
+  LVector3 get_wind_velocity() const;
+
   void set_pose(bool bvolume, bool bframe);
 
   BoundingBox get_aabb() const;

+ 56 - 7
panda/src/bullet/bulletWorld.cxx

@@ -87,18 +87,21 @@ BulletWorld() {
   // Filter callback
   switch (bullet_filter_algorithm) {
     case FA_mask:
-      _world->getPairCache()->setOverlapFilterCallback(&_filter_cb1);
+      _filter_cb = &_filter_cb1;
       break;
     case FA_groups_mask:
-      _world->getPairCache()->setOverlapFilterCallback(&_filter_cb2);
+      _filter_cb = &_filter_cb2;
       break;
     case FA_callback:
-      _world->getPairCache()->setOverlapFilterCallback(&_filter_cb3);
+      _filter_cb = &_filter_cb3;
       break;
     default:
       bullet_cat.error() << "no proper filter algorithm!" << endl;
+      _filter_cb = NULL;
   }
 
+  _world->getPairCache()->setOverlapFilterCallback(_filter_cb);
+
   // Tick callback
   _tick_callback_obj = NULL;
 
@@ -712,19 +715,61 @@ sweep_test_closest(BulletShape *shape, const TransformState &from_ts, const Tran
   return cb;  
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BulletWorld::filter_test
+//       Access: Published
+//  Description: Performs a test if two bodies should collide or
+//               not, based on the collision filter setting.
+////////////////////////////////////////////////////////////////////
+bool BulletWorld::
+filter_test(PandaNode *node0, PandaNode *node1) const {
+
+  nassertr(node0, false);
+  nassertr(node1, false);
+  nassertr(_filter_cb, false);
+
+  btCollisionObject *obj0 = get_collision_object(node0);
+  btCollisionObject *obj1 = get_collision_object(node1);
+
+  nassertr(obj0, false);
+  nassertr(obj1, false);
+
+  btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle();
+  btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle();
+
+  nassertr(proxy0, false);
+  nassertr(proxy1, false);
+
+  return _filter_cb->needBroadphaseCollision(proxy0, proxy1);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletWorld::contact_test
 //       Access: Published
-//  Description: 
+//  Description: Performas a test for all bodies which are
+//               currently in contact with the given body.
+//               The test returns a BulletContactResult object
+//               which may contain zero, one or more contacts.
+//
+//               If the optional parameter use_filter is set to
+//               TRUE this test will consider filter settings.
+//               Otherwise all objects in contact are reported,
+//               no matter if they would collide or not.
 ////////////////////////////////////////////////////////////////////
 BulletContactResult BulletWorld::
-contact_test(PandaNode *node) const {
+contact_test(PandaNode *node, bool use_filter) const {
 
   btCollisionObject *obj = get_collision_object(node);
 
   BulletContactResult cb;
 
   if (obj) {
+#if BT_BULLET_VERSION >= 281
+    if (use_filter) {
+      cb.use_filter(_filter_cb, obj->getBroadphaseHandle());
+    }
+#endif
+
     _world->contactTest(obj, cb);
   }
 
@@ -734,7 +779,10 @@ contact_test(PandaNode *node) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: BulletWorld::contact_pair_test
 //       Access: Published
-//  Description: 
+//  Description: Performas a test if the two bodies given as
+//               parameters are in contact or not.
+//               The test returns a BulletContactResult object
+//               which may contain zero or one contacts.
 ////////////////////////////////////////////////////////////////////
 BulletContactResult BulletWorld::
 contact_test_pair(PandaNode *node0, PandaNode *node1) const {
@@ -745,6 +793,7 @@ contact_test_pair(PandaNode *node0, PandaNode *node1) const {
   BulletContactResult cb;
 
   if (obj0 && obj1) {
+
     _world->contactPairTest(obj0, obj1, cb);
   }
 
@@ -806,7 +855,7 @@ set_group_collision_flag(unsigned int group1, unsigned int group2, bool enable)
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BulletWorld::get_collision_object
+//     Function: BulletWorld::get_group_collision_flag
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////

+ 4 - 1
panda/src/bullet/bulletWorld.h

@@ -123,9 +123,11 @@ PUBLISHED:
     const CollideMask &mask=CollideMask::all_on(),
     PN_stdfloat penetration=0.0f) const;
 
-  BulletContactResult contact_test(PandaNode *node) const;
+  BulletContactResult contact_test(PandaNode *node, bool use_filter=false) const;
   BulletContactResult contact_test_pair(PandaNode *node0, PandaNode *node1) const;
 
+  bool filter_test(PandaNode *node0, PandaNode *node1) const;
+
   // Manifolds
   INLINE int get_num_manifolds() const;
   BulletPersistentManifold *get_manifold(int idx) const;
@@ -232,6 +234,7 @@ private:
   btFilterCallback1 _filter_cb1;
   btFilterCallback2 _filter_cb2;
   btFilterCallback3 _filter_cb3;
+  btOverlapFilterCallback *_filter_cb;
 
   PT(CallbackObject) _tick_callback_obj;
 

+ 1 - 1
panda/src/chan/partGroup.h

@@ -43,7 +43,7 @@ class AnimChannelBase;
 //               MovingPart.  It defines a hierarchy of MovingParts.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_CHAN PartGroup : public TypedWritableReferenceCount, public Namable {
-public:
+PUBLISHED:
   // This enum defines bits which may be passed into check_hierarchy()
   // and PartBundle::bind_anim() to allow an inexact match of channel
   // hierarchies.  This specifies conditions that we don't care about

+ 2 - 1
panda/src/cocoadisplay/Sources.pp

@@ -17,13 +17,14 @@
      cocoaGraphicsPipe.h cocoaGraphicsPipe.I \
      cocoaGraphicsWindow.h cocoaGraphicsWindow.I \
      cocoaGraphicsStateGuardian.h cocoaGraphicsStateGuardian.I \
-     cocoaPandaView.h cocoaPandaWindowDelegate.h
+     cocoaPandaApp.h cocoaPandaView.h cocoaPandaWindowDelegate.h
     
   #define INCLUDED_SOURCES \
     config_cocoadisplay.mm \
     cocoaGraphicsPipe.mm \
     cocoaGraphicsStateGuardian.mm \
     cocoaGraphicsWindow.mm \
+    cocoaPandaApp.mm \
     cocoaPandaView.mm \
     cocoaPandaWindow.mm \
     cocoaPandaWindowDelegate.mm

+ 2 - 1
panda/src/cocoadisplay/cocoaGraphicsPipe.mm

@@ -16,6 +16,7 @@
 //#include "cocoaGraphicsBuffer.h"
 #include "cocoaGraphicsWindow.h"
 #include "cocoaGraphicsStateGuardian.h"
+#include "cocoaPandaApp.h"
 #include "config_cocoadisplay.h"
 #include "frameBufferProperties.h"
 
@@ -32,7 +33,7 @@ TypeHandle CocoaGraphicsPipe::_type_handle;
 static void init_app() {
   if (NSApp == nil) {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    [NSApplication sharedApplication];
+    [CocoaPandaApp sharedApplication];
 
 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

+ 3 - 1
panda/src/cocoadisplay/cocoaGraphicsWindow.h

@@ -80,7 +80,9 @@ protected:
 private:
   NSImage *load_image(const Filename &filename);
 
-  ButtonHandle map_key(unsigned short keycode);
+  void handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button);
+  ButtonHandle map_key(unsigned short c);
+  ButtonHandle map_raw_key(unsigned short keycode);
 
 private:
   NSWindow *_window;

+ 208 - 46
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -1495,54 +1495,73 @@ void CocoaGraphicsWindow::
 handle_key_event(NSEvent *event) {
   NSUInteger modifierFlags = [event modifierFlags];
 
-  if ((modifierFlags ^ _modifier_keys) & NSAlphaShiftKeyMask) {
-    if (modifierFlags & NSAlphaShiftKeyMask) {
-      _input_devices[0].button_down(KeyboardButton::caps_lock());
-    } else {
-      _input_devices[0].button_up(KeyboardButton::caps_lock());
-    }
-  }
-
-  if ((modifierFlags ^ _modifier_keys) & NSShiftKeyMask) {
-    if (modifierFlags & NSShiftKeyMask) {
-      _input_devices[0].button_down(KeyboardButton::shift());
-    } else {
-      _input_devices[0].button_up(KeyboardButton::shift());
-    }
-  }
-
-  if ((modifierFlags ^ _modifier_keys) & NSControlKeyMask) {
-    if (modifierFlags & NSControlKeyMask) {
-      _input_devices[0].button_down(KeyboardButton::control());
-    } else {
-      _input_devices[0].button_up(KeyboardButton::control());
-    }
-  }
+  //NB.  This is actually a on-off toggle, not up-down.
+  // Should we instead rapidly fire two successive up-down events?
+  handle_modifier(modifierFlags, NSAlphaShiftKeyMask, KeyboardButton::caps_lock());
+
+  // Check if any of the modifier keys have changed.
+  handle_modifier(modifierFlags, NSShiftKeyMask, KeyboardButton::shift());
+  handle_modifier(modifierFlags, NSControlKeyMask, KeyboardButton::control());
+  handle_modifier(modifierFlags, NSAlternateKeyMask, KeyboardButton::alt());
+  handle_modifier(modifierFlags, NSCommandKeyMask, KeyboardButton::meta());
+
+  // These are not documented, but they seem to be a reliable indicator
+  // of the status of the left/right modifier keys.
+  handle_modifier(modifierFlags, 0x0002, KeyboardButton::lshift());
+  handle_modifier(modifierFlags, 0x0004, KeyboardButton::rshift());
+  handle_modifier(modifierFlags, 0x0001, KeyboardButton::lcontrol());
+  handle_modifier(modifierFlags, 0x2000, KeyboardButton::rcontrol());
+  handle_modifier(modifierFlags, 0x0020, KeyboardButton::lalt());
+  handle_modifier(modifierFlags, 0x0040, KeyboardButton::ralt());
+  handle_modifier(modifierFlags, 0x0008, KeyboardButton::lmeta());
+  handle_modifier(modifierFlags, 0x0010, KeyboardButton::rmeta());
 
-  if ((modifierFlags ^ _modifier_keys) & NSAlternateKeyMask) {
-    if (modifierFlags & NSAlternateKeyMask) {
-      _input_devices[0].button_down(KeyboardButton::alt());
-    } else {
-      _input_devices[0].button_up(KeyboardButton::alt());
-    }
-  }
+  _modifier_keys = modifierFlags;
 
-  if ((modifierFlags ^ _modifier_keys) & NSCommandKeyMask) {
-    if (modifierFlags & NSCommandKeyMask) {
-      _input_devices[0].button_down(KeyboardButton::meta());
-    } else {
-      _input_devices[0].button_up(KeyboardButton::meta());
+  // Get the raw button and send it.
+  ButtonHandle raw_button = map_raw_key([event keyCode]);
+  if (raw_button != ButtonHandle::none()) {
+    // This is not perfect.  Eventually, this whole thing should
+    // probably be replaced with something that uses IOKit or so.
+    // In particular, the flaws are:
+    // - OS eats unmodified F11, F12, scroll lock, pause
+    // - no up events for caps lock
+    // - no robust way to distinguish up/down for modkeys
+    if ([event type] == NSKeyUp) {
+      _input_devices[0].raw_button_up(raw_button);
+
+    } else if ([event type] == NSFlagsChanged) {
+      bool down = false;
+      if (raw_button == KeyboardButton::lshift()) {
+        down = (modifierFlags & 0x0002);
+      } else if (raw_button == KeyboardButton::rshift()) {
+        down = (modifierFlags & 0x0004);
+      } else if (raw_button == KeyboardButton::lcontrol()) {
+        down = (modifierFlags & 0x0001);
+      } else if (raw_button == KeyboardButton::rcontrol()) {
+        down = (modifierFlags & 0x2000);
+      } else if (raw_button == KeyboardButton::lalt()) {
+        down = (modifierFlags & 0x0020);
+      } else if (raw_button == KeyboardButton::ralt()) {
+        down = (modifierFlags & 0x0040);
+      } else if (raw_button == KeyboardButton::lmeta()) {
+        down = (modifierFlags & 0x0008);
+      } else if (raw_button == KeyboardButton::rmeta()) {
+        down = (modifierFlags & 0x0010);
+      } else if (raw_button == KeyboardButton::caps_lock()) {
+        // Emulate down-up, annoying hack!
+        _input_devices[0].raw_button_down(raw_button);
+      }
+      if (down) {
+        _input_devices[0].raw_button_down(raw_button);
+      } else {
+        _input_devices[0].raw_button_up(raw_button);
+      }
+    } else if (![event isARepeat]) {
+      _input_devices[0].raw_button_down(raw_button);
     }
   }
 
-  // I'd add the help key too, but something else in Cocoa messes
-  // around with it.  The up event is registered fine below, but
-  // the down event isn't, and the modifier flag gets stuck after 1 press.
-  // More testing is needed, but I don't think it's worth it until
-  // we encounter someone who requires support for the help key.
-
-  _modifier_keys = modifierFlags;
-
   // FlagsChanged events only carry modifier key information.
   if ([event type] == NSFlagsChanged) {
     return;
@@ -1597,6 +1616,23 @@ handle_key_event(NSEvent *event) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CocoaGraphicsWindow::handle_modifier
+//       Access: Private
+//  Description: Called by handle_key_event to read the state of
+//               a modifier key.
+////////////////////////////////////////////////////////////////////
+void CocoaGraphicsWindow::
+handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button) {
+  if ((modifierFlags ^ _modifier_keys) & mask) {
+    if (modifierFlags & mask) {
+      _input_devices[0].button_down(button);
+    } else {
+      _input_devices[0].button_up(button);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CocoaGraphicsWindow::handle_mouse_button_event
 //       Access: Public
@@ -1697,11 +1733,11 @@ handle_wheel_event(double x, double y) {
 ////////////////////////////////////////////////////////////////////
 //     Function: CocoaGraphicsWindow::map_key
 //       Access: Private
-//  Description:
+//  Description: Maps a Cocoa key character to a ButtonHandle.
 ////////////////////////////////////////////////////////////////////
 ButtonHandle CocoaGraphicsWindow::
-map_key(unsigned short keycode) {
-  switch (keycode) {
+map_key(unsigned short c) {
+  switch (c) {
   case NSEnterCharacter:
     return KeyboardButton::enter();
   case NSBackspaceCharacter:
@@ -1713,6 +1749,11 @@ map_key(unsigned short keycode) {
     // BackTabCharacter is sent when shift-tab is used.
     return KeyboardButton::tab();
 
+  case 16:
+    // No idea where this constant comes from, but it
+    // is sent whenever the menu key is pressed.
+    return KeyboardButton::menu();
+
   case NSUpArrowFunctionKey:
     return KeyboardButton::up();
   case NSDownArrowFunctionKey:
@@ -1824,3 +1865,124 @@ map_key(unsigned short keycode) {
   }
   return ButtonHandle::none();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: CocoaGraphicsWindow::map_raw_key
+//       Access: Private
+//  Description: Maps a keycode to a ButtonHandle.
+////////////////////////////////////////////////////////////////////
+ButtonHandle CocoaGraphicsWindow::
+map_raw_key(unsigned short keycode) {
+  if (keycode > 0x7f) {
+    return ButtonHandle::none();
+  }
+  switch ((unsigned char) keycode) {
+  /* See HIToolBox/Events.h */
+  case 0x00: return KeyboardButton::ascii_key('a');
+  case 0x01: return KeyboardButton::ascii_key('s');
+  case 0x02: return KeyboardButton::ascii_key('d');
+  case 0x03: return KeyboardButton::ascii_key('f');
+  case 0x04: return KeyboardButton::ascii_key('h');
+  case 0x05: return KeyboardButton::ascii_key('g');
+  case 0x06: return KeyboardButton::ascii_key('z');
+  case 0x07: return KeyboardButton::ascii_key('x');
+  case 0x08: return KeyboardButton::ascii_key('c');
+  case 0x09: return KeyboardButton::ascii_key('v');
+  case 0x0B: return KeyboardButton::ascii_key('b');
+  case 0x0C: return KeyboardButton::ascii_key('q');
+  case 0x0D: return KeyboardButton::ascii_key('w');
+  case 0x0E: return KeyboardButton::ascii_key('e');
+  case 0x0F: return KeyboardButton::ascii_key('r');
+  case 0x10: return KeyboardButton::ascii_key('y');
+  case 0x11: return KeyboardButton::ascii_key('t');
+  case 0x12: return KeyboardButton::ascii_key('1');
+  case 0x13: return KeyboardButton::ascii_key('2');
+  case 0x14: return KeyboardButton::ascii_key('3');
+  case 0x15: return KeyboardButton::ascii_key('4');
+  case 0x16: return KeyboardButton::ascii_key('6');
+  case 0x17: return KeyboardButton::ascii_key('5');
+  case 0x18: return KeyboardButton::ascii_key('=');
+  case 0x19: return KeyboardButton::ascii_key('9');
+  case 0x1A: return KeyboardButton::ascii_key('7');
+  case 0x1B: return KeyboardButton::ascii_key('-');
+  case 0x1C: return KeyboardButton::ascii_key('8');
+  case 0x1D: return KeyboardButton::ascii_key('0');
+  case 0x1E: return KeyboardButton::ascii_key(']');
+  case 0x1F: return KeyboardButton::ascii_key('o');
+  case 0x20: return KeyboardButton::ascii_key('u');
+  case 0x21: return KeyboardButton::ascii_key('[');
+  case 0x22: return KeyboardButton::ascii_key('i');
+  case 0x23: return KeyboardButton::ascii_key('p');
+  case 0x24: return KeyboardButton::enter();
+  case 0x25: return KeyboardButton::ascii_key('l');
+  case 0x26: return KeyboardButton::ascii_key('j');
+  case 0x27: return KeyboardButton::ascii_key('\'');
+  case 0x28: return KeyboardButton::ascii_key('k');
+  case 0x29: return KeyboardButton::ascii_key(';');
+  case 0x2A: return KeyboardButton::ascii_key('\\');
+  case 0x2B: return KeyboardButton::ascii_key(',');
+  case 0x2C: return KeyboardButton::ascii_key('/');
+  case 0x2D: return KeyboardButton::ascii_key('n');
+  case 0x2E: return KeyboardButton::ascii_key('m');
+  case 0x2F: return KeyboardButton::ascii_key('.');
+  case 0x30: return KeyboardButton::tab();
+  case 0x31: return KeyboardButton::ascii_key(' ');
+  case 0x32: return KeyboardButton::ascii_key('`');
+  case 0x33: return KeyboardButton::backspace();
+  case 0x35: return KeyboardButton::escape();
+  case 0x36: return KeyboardButton::rmeta();
+  case 0x37: return KeyboardButton::lmeta();
+  case 0x38: return KeyboardButton::lshift();
+  case 0x39: return KeyboardButton::caps_lock();
+  case 0x3A: return KeyboardButton::lalt();
+  case 0x3B: return KeyboardButton::lcontrol();
+  case 0x3C: return KeyboardButton::rshift();
+  case 0x3D: return KeyboardButton::ralt();
+  case 0x3E: return KeyboardButton::rcontrol();
+  case 0x41: return KeyboardButton::ascii_key('.');
+  case 0x43: return KeyboardButton::ascii_key('*');
+  case 0x45: return KeyboardButton::ascii_key('+');
+  case 0x47: return KeyboardButton::num_lock();
+  case 0x4B: return KeyboardButton::ascii_key('/');
+  case 0x4C: return KeyboardButton::enter();
+  case 0x4E: return KeyboardButton::ascii_key('-');
+  case 0x51: return KeyboardButton::ascii_key('=');
+  case 0x52: return KeyboardButton::ascii_key('0');
+  case 0x53: return KeyboardButton::ascii_key('1');
+  case 0x54: return KeyboardButton::ascii_key('2');
+  case 0x55: return KeyboardButton::ascii_key('3');
+  case 0x56: return KeyboardButton::ascii_key('4');
+  case 0x57: return KeyboardButton::ascii_key('5');
+  case 0x58: return KeyboardButton::ascii_key('6');
+  case 0x59: return KeyboardButton::ascii_key('7');
+  case 0x5B: return KeyboardButton::ascii_key('8');
+  case 0x5C: return KeyboardButton::ascii_key('9');
+  case 0x60: return KeyboardButton::f5();
+  case 0x61: return KeyboardButton::f6();
+  case 0x62: return KeyboardButton::f7();
+  case 0x63: return KeyboardButton::f3();
+  case 0x64: return KeyboardButton::f8();
+  case 0x65: return KeyboardButton::f9();
+  case 0x67: return KeyboardButton::f11();
+  case 0x69: return KeyboardButton::print_screen();
+  case 0x6B: return KeyboardButton::scroll_lock();
+  case 0x6D: return KeyboardButton::f10();
+  case 0x6E: return KeyboardButton::menu();
+  case 0x6F: return KeyboardButton::f12();
+  case 0x71: return KeyboardButton::pause();
+  case 0x72: return KeyboardButton::insert();
+  case 0x73: return KeyboardButton::home();
+  case 0x74: return KeyboardButton::page_up();
+  case 0x75: return KeyboardButton::del();
+  case 0x76: return KeyboardButton::f4();
+  case 0x77: return KeyboardButton::end();
+  case 0x78: return KeyboardButton::f2();
+  case 0x79: return KeyboardButton::page_down();
+  case 0x7A: return KeyboardButton::f1();
+  case 0x7B: return KeyboardButton::left();
+  case 0x7C: return KeyboardButton::right();
+  case 0x7D: return KeyboardButton::down();
+  case 0x7E: return KeyboardButton::up();
+  default:   return ButtonHandle::none();
+  }
+}

+ 21 - 0
panda/src/cocoadisplay/cocoaPandaApp.h

@@ -0,0 +1,21 @@
+// Filename: cocoaPandaApp.h
+// Created by:  rdb (08Mar14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#import <AppKit/NSApplication.h>
+
+// This class solely exists so that we can override sendEvent in order
+// to prevent NSApplication from eating certain keyboard events.
+@interface CocoaPandaApp : NSApplication
+- (void) sendEvent: (NSEvent *) event;
+@end

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

@@ -0,0 +1,29 @@
+// Filename: cocoaPandaApp.mm
+// Created by:  rdb (08Mar14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#import "cocoaPandaApp.h"
+
+@implementation CocoaPandaApp
+- (void) sendEvent: (NSEvent *) event {
+  // This is a hack that allows us to receive cmd-key-up events correctly.
+  // Also prevent it from eating the insert/help key.
+  if (([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask))
+    ||([event type] == NSKeyDown && [event keyCode] == 0x72)) {
+
+    [[self keyWindow] sendEvent: event];
+  } else {
+    [super sendEvent: event];
+  }
+}
+@end

+ 2 - 1
panda/src/cocoadisplay/p3cocoadisplay_composite1.mm

@@ -2,6 +2,7 @@
 #include "cocoaGraphicsPipe.mm"
 #include "cocoaGraphicsStateGuardian.mm"
 #include "cocoaGraphicsWindow.mm"
+#include "cocoaPandaApp.mm"
 #include "cocoaPandaView.mm"
 #include "cocoaPandaWindow.mm"
-#include "cocoaPandaWindowDelegate.mm"
+#include "cocoaPandaWindowDelegate.mm"

+ 2 - 2
panda/src/display/Sources.pp

@@ -27,8 +27,8 @@
     graphicsDevice.h graphicsDevice.I \
     graphicsPipe.I graphicsPipe.h  \
     graphicsPipeSelection.I graphicsPipeSelection.h \
-    graphicsStateGuardian.I \
-    graphicsStateGuardian.h \
+    graphicsStateGuardian.I graphicsStateGuardian.h \
+    graphicsStateGuardian_ext.cxx graphicsStateGuardian_ext.h \
     graphicsThreadingModel.I graphicsThreadingModel.h \
     graphicsWindow.I graphicsWindow.h \
     graphicsWindowInputDevice.I  \

+ 28 - 51
panda/src/display/graphicsStateGuardian.cxx

@@ -59,13 +59,6 @@
 #include <algorithm>
 #include <limits.h>
 
-#ifdef HAVE_PYTHON
-#include "py_panda.h"
-#ifndef CPPPARSER
-IMPORT_THIS struct Dtool_PyTypedObject Dtool_Texture;
-#endif
-#endif  // HAVE_PYTHON
-
 PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
 PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
 PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
@@ -247,10 +240,10 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   // The default is no shader support.
   _auto_detect_shader_model = SM_00;
   _shader_model = SM_00;
-  
+
   _gamma = 1.0f;
   _texture_quality_override = Texture::QL_default;
-  
+
   _shader_generator = NULL;
 }
 
@@ -435,41 +428,6 @@ void GraphicsStateGuardian::
 restore_gamma() {
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::get_prepared_textures
-//       Access: Published
-//  Description: Returns a Python list of all of the
-//               currently-prepared textures within the GSG.
-////////////////////////////////////////////////////////////////////
-PyObject *GraphicsStateGuardian::
-get_prepared_textures() const {
-  ReMutexHolder holder(_prepared_objects->_lock);
-  size_t num_textures = _prepared_objects->_prepared_textures.size();
-  PyObject *list = PyList_New(num_textures);
-
-  size_t i = 0;
-  PreparedGraphicsObjects::Textures::const_iterator ti;
-  for (ti = _prepared_objects->_prepared_textures.begin();
-       ti != _prepared_objects->_prepared_textures.end();
-       ++ti) {
-    PT(Texture) tex = (*ti)->get_texture();
-
-    PyObject *element = 
-      DTool_CreatePyInstanceTyped(tex, Dtool_Texture,
-                                  true, false, tex->get_type_index());
-    tex->ref();
-
-    nassertr(i < num_textures, NULL);
-    PyList_SetItem(list, i, element);
-    ++i;
-  }
-  nassertr(i == num_textures, NULL);
-
-  return list;
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::traverse_prepared_textures
 //       Access: Public
@@ -485,7 +443,7 @@ traverse_prepared_textures(GraphicsStateGuardian::TextureCallback *func,
   for (ti = _prepared_objects->_prepared_textures.begin();
        ti != _prepared_objects->_prepared_textures.end();
        ++ti) {
-    bool result = (*func)(*ti,callback_arg);
+    bool result = (*func)(*ti, callback_arg);
     if (!result) {
       return;
     }
@@ -996,6 +954,16 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4 &
                                  0.0);
     return &t;
   }
+  case Shader::SMO_frame_time: {
+    PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time();
+    t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time);
+    return &t;
+  }
+  case Shader::SMO_frame_delta: {
+    PN_stdfloat dt = ClockObject::get_global_clock()->get_dt();
+    t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt);
+    return &t;
+  }
   case Shader::SMO_texpad_x: {
     Texture *tex = _target_shader->get_shader_input_texture(name);
     nassertr(tex != 0, &LMatrix4::zeros_mat());
@@ -2463,11 +2431,11 @@ determine_target_texture() {
            target_tex_gen != (TexGenAttrib *)NULL);
   _target_texture = target_texture;
   _target_tex_gen = target_tex_gen;
-  
+
   if (_has_texture_alpha_scale) {
     PT(TextureStage) stage = get_alpha_scale_texture_stage();
     PT(Texture) texture = TexturePool::get_alpha_scale_map();
-    
+
     _target_texture = DCAST(TextureAttrib, _target_texture->add_on_stage(stage, texture));
     _target_tex_gen = DCAST(TexGenAttrib, _target_tex_gen->add_stage
                                (stage, TexGenAttrib::M_constant, LTexCoord3(_current_color_scale[3], 0.0f, 0.0f)));
@@ -2791,6 +2759,9 @@ string GraphicsStateGuardian::get_driver_renderer() {
 //     Function: GraphicsStateGuardian::get_driver_version
 //       Access: Public, Virtual
 //  Description: Returns driver version
+//               This has an implementation-defined meaning, and may
+//               be "0" if the particular graphics implementation
+//               does not provide a way to query this information.
 ////////////////////////////////////////////////////////////////////
 string GraphicsStateGuardian::
 get_driver_version() {
@@ -2800,7 +2771,10 @@ get_driver_version() {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_driver_version_major
 //       Access: Public, Virtual
-//  Description: Returns major version of the video driver
+//  Description: Returns major version of the video driver.
+//               This has an implementation-defined meaning, and may
+//               be -1 if the particular graphics implementation
+//               does not provide a way to query this information.
 ////////////////////////////////////////////////////////////////////
 int GraphicsStateGuardian::
 get_driver_version_major() {
@@ -2810,7 +2784,10 @@ get_driver_version_major() {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_driver_version_minor
 //       Access: Public, Virtual
-//  Description: Returns the minor version of the video driver
+//  Description: Returns the minor version of the video driver.
+//               This has an implementation-defined meaning, and may
+//               be -1 if the particular graphics implementation
+//               does not provide a way to query this information.
 ////////////////////////////////////////////////////////////////////
 int GraphicsStateGuardian::
 get_driver_version_minor() {
@@ -2820,7 +2797,7 @@ get_driver_version_minor() {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_driver_shader_version_major
 //       Access: Public, Virtual
-//  Description: Returns the major version of the shader model
+//  Description: Returns the major version of the shader model.
 ////////////////////////////////////////////////////////////////////
 int GraphicsStateGuardian::
 get_driver_shader_version_major() {
@@ -2830,7 +2807,7 @@ get_driver_shader_version_major() {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_driver_shader_version_minor
 //       Access: Public, Virtual
-//  Description: Returns the minor version of the shader model
+//  Description: Returns the minor version of the shader model.
 ////////////////////////////////////////////////////////////////////
 int GraphicsStateGuardian::
 get_driver_shader_version_minor() {

+ 3 - 5
panda/src/display/graphicsStateGuardian.h

@@ -46,9 +46,9 @@
 #include "occlusionQueryContext.h"
 #include "stencilRenderStates.h"
 #include "loader.h"
-#include "textureAttrib.h"
-#include "texGenAttrib.h"
 #include "shaderAttrib.h"
+#include "texGenAttrib.h"
+#include "textureAttrib.h"
 
 class DrawableRegion;
 class GraphicsEngine;
@@ -179,9 +179,7 @@ PUBLISHED:
   INLINE void set_texture_quality_override(Texture::QualityLevel quality_level);
   INLINE Texture::QualityLevel get_texture_quality_override() const;
 
-#ifdef HAVE_PYTHON
-  PyObject *get_prepared_textures() const;
-#endif
+  EXTENSION(PyObject *get_prepared_textures() const);
   typedef bool TextureCallback(TextureContext *tc, void *callback_arg);
   void traverse_prepared_textures(TextureCallback *func, void *callback_arg);
 

+ 55 - 0
panda/src/display/graphicsStateGuardian_ext.cxx

@@ -0,0 +1,55 @@
+// Filename: graphicsStateGuardian_ext.cxx
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "graphicsStateGuardian_ext.h"
+#include "textureContext.h"
+
+#ifdef HAVE_PYTHON
+
+#ifndef CPPPARSER
+IMPORT_THIS struct Dtool_PyTypedObject Dtool_Texture;
+#endif
+
+static bool traverse_callback(TextureContext *tc, void *data) {
+  PT(Texture) tex = tc->get_texture();
+  PyObject *element =
+    DTool_CreatePyInstanceTyped(tex, Dtool_Texture,
+                                true, false, tex->get_type_index());
+  tex->ref();
+
+  PyObject *list = (PyObject *) data;
+  PyList_Append(list, element);
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_prepared_textures
+//       Access: Published
+//  Description: Returns a Python list of all of the
+//               currently-prepared textures within the GSG.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<GraphicsStateGuardian>::
+get_prepared_textures() const {
+  PyObject *list = PyList_New(0);
+
+  if (list == NULL) {
+    return NULL;
+  }
+
+  _this->traverse_prepared_textures(&traverse_callback, (void *)list);
+  return list;
+}
+
+#endif

+ 40 - 0
panda/src/display/graphicsStateGuardian_ext.h

@@ -0,0 +1,40 @@
+// Filename: graphicsStateGuardian_ext.h
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GRAPHICSSTATEGUARDIAN_EXT_H
+#define GRAPHICSSTATEGUARDIAN_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "graphicsStateGuardian.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<GraphicsStateGuardian>
+// Description : This class defines the extension methods for
+//               Ramfile, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<GraphicsStateGuardian> : public ExtensionBase<GraphicsStateGuardian> {
+public:
+  PyObject *get_prepared_textures() const;
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // GRAPHICSSTATEGUARDIAN_EXT_H

+ 22 - 0
panda/src/display/graphicsWindowInputDevice.cxx

@@ -366,3 +366,25 @@ focus_lost(double time) {
   }
   _buttons_held.clear();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::raw_button_down
+//       Access: Public
+//  Description: Records that the indicated button has been depressed.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindowInputDevice::
+raw_button_down(ButtonHandle button, double time) {
+  LightMutexHolder holder(_lock);
+  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_down, time));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::raw_button_up
+//       Access: Public
+//  Description: Records that the indicated button has been released.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindowInputDevice::
+raw_button_up(ButtonHandle button, double time) {
+  LightMutexHolder holder(_lock);
+  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_raw_up, time));
+}

+ 12 - 10
panda/src/display/graphicsWindowInputDevice.h

@@ -47,27 +47,27 @@ public:
   static GraphicsWindowInputDevice pointer_only(GraphicsWindow *host, const string &name);
   static GraphicsWindowInputDevice keyboard_only(GraphicsWindow *host, const string &name);
   static GraphicsWindowInputDevice pointer_and_keyboard(GraphicsWindow *host, const string &name);
-  
+
   INLINE GraphicsWindowInputDevice();
   GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy);
   void operator = (const GraphicsWindowInputDevice &copy);
   ~GraphicsWindowInputDevice();
-  
+
   INLINE string get_name() const;
   INLINE bool has_pointer() const;
   INLINE bool has_keyboard() const;
 
   INLINE void set_device_index(int index);
-  
+
   INLINE MouseData get_pointer() const;
   INLINE MouseData get_raw_pointer() const;
-  
+
   INLINE void enable_pointer_events();
   INLINE void disable_pointer_events();
-  
+
   void enable_pointer_mode(double speed);
   void disable_pointer_mode();
-  
+
   bool has_button_event() const;
   ButtonEvent get_button_event();
   bool has_pointer_event() const;
@@ -83,6 +83,8 @@ PUBLISHED:
   void candidate(const wstring &candidate_string, size_t highlight_start, 
                  size_t highlight_end, size_t cursor_pos);
   void focus_lost(double time = ClockObject::get_global_clock()->get_frame_time());
+  void raw_button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+  void raw_button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
 
   INLINE void set_pointer_in_window(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
   INLINE void set_pointer_out_of_window(double time = ClockObject::get_global_clock()->get_frame_time());
@@ -104,17 +106,17 @@ private:
   typedef pdeque<ButtonEvent> ButtonEvents;
 
   LightMutex _lock;
-  
+
   GraphicsWindow *_host;
-  
+
   string _name;
   int _flags;
   int _device_index;
   int _event_sequence;
-  
+
   bool   _pointer_mode_enable;
   double _pointer_speed;
-  
+
   bool _enable_pointer_events;
   MouseData _mouse_data;
   MouseData _true_mouse_data;

+ 5 - 2
panda/src/egg/Sources.pp

@@ -24,6 +24,7 @@
      eggCurve.I eggCurve.h eggData.I eggData.h  \
      eggExternalReference.I eggExternalReference.h  \
      eggFilenameNode.I eggFilenameNode.h eggGroup.I eggGroup.h  \
+     eggGroupNode_ext.h \
      eggGroupNode.I eggGroupNode.h eggGroupUniquifier.h  \
      eggLine.I eggLine.h \
      eggMaterial.I eggMaterial.h eggMaterialCollection.I  \
@@ -69,7 +70,8 @@
      eggCompositePrimitive.cxx \
      eggCoordinateSystem.cxx  \
      eggCurve.cxx eggData.cxx eggExternalReference.cxx  \
-     eggFilenameNode.cxx eggGroup.cxx eggGroupNode.cxx  \
+     eggFilenameNode.cxx eggGroup.cxx  \
+     eggGroupNode_ext.cxx eggGroupNode.cxx  \
      eggGroupUniquifier.cxx eggLine.cxx eggMaterial.cxx  \
      eggMaterialCollection.cxx \
      eggMesher.cxx \
@@ -106,7 +108,8 @@
     eggCoordinateSystem.I eggCoordinateSystem.h eggCurve.I \
     eggCurve.h eggData.I eggData.h eggExternalReference.I \
     eggExternalReference.h eggFilenameNode.I eggFilenameNode.h \
-    eggGroup.I eggGroup.h eggGroupNode.I eggGroupNode.h \
+    eggGroup.I eggGroup.h \
+    eggGroupNode_ext.h eggGroupNode.I eggGroupNode.h \
     eggGroupUniquifier.h \
     eggLine.I eggLine.h \
     eggMaterial.I \

+ 2 - 0
panda/src/egg/eggGroupNode.h

@@ -113,6 +113,8 @@ PUBLISHED:
   EggNode *get_first_child();
   EggNode *get_next_child();
 
+  EXTENSION(PyObject *get_children() const);
+
   EggNode *add_child(EggNode *node);
   PT(EggNode) remove_child(EggNode *node);
   void steal_children(EggGroupNode &other);

+ 51 - 0
panda/src/egg/eggGroupNode_ext.cxx

@@ -0,0 +1,51 @@
+// Filename: eggGroupNode_ext.cxx
+// Created by:  rdb (09Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eggGroupNode_ext.h"
+
+#ifdef HAVE_PYTHON
+
+IMPORT_THIS struct Dtool_PyTypedObject Dtool_EggNode;
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroupNode::get_children
+//       Access: Published
+//  Description: Returns a Python list containing the node's children.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<EggGroupNode>::
+get_children() const {
+  EggGroupNode::iterator it;
+
+  // Create the Python list object.
+  EggGroupNode::size_type len = _this->size();
+  PyObject *lst = PyList_New(len);
+  if (lst == NULL) {
+    return NULL;
+  }
+
+  // Fill in the list.
+  int i = 0;
+  for (it = _this->begin(); it != _this->end() && i < len; ++it) {
+    EggNode *node = *it;
+    node->ref();
+    PyObject *item =
+      DTool_CreatePyInstanceTyped((void *)node, Dtool_EggNode, true, false, node->get_type_index());
+
+    PyList_SET_ITEM(lst, i++, item);
+  }
+
+  return lst;
+}
+
+#endif  // HAVE_PYTHON

+ 40 - 0
panda/src/egg/eggGroupNode_ext.h

@@ -0,0 +1,40 @@
+// Filename: eggGroupNode_ext.h
+// Created by:  rdb (09Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EGGGROUPNODE_EXT_H
+#define EGGGROUPNODE_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "eggGroupNode.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<EggGroupNode>
+// Description : This class defines the extension methods for
+//               EggGroupNode, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<EggGroupNode> : public ExtensionBase<EggGroupNode> {
+public:
+  PyObject *get_children() const;
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // EGGGROUPNODE_EXT_H

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

@@ -58,6 +58,6 @@ public:
   double _table_threshold;
 };
 
-extern EggParameters *egg_parameters;
+extern EXPCL_PANDAEGG EggParameters *egg_parameters;
 
 #endif

+ 28 - 19
panda/src/egldisplay/eglGraphicsWindow.cxx

@@ -1215,16 +1215,19 @@ handle_keypress(XKeyEvent &event) {
 
   // Now get the raw unshifted button.
   ButtonHandle button = get_button(event, false);
-  if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
-    _input_devices[0].button_down(KeyboardButton::control());
-  }
-  if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
-    _input_devices[0].button_down(KeyboardButton::shift());
-  }
-  if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
-    _input_devices[0].button_down(KeyboardButton::alt());
-  }
   if (button != ButtonHandle::none()) {
+    if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
+      _input_devices[0].button_down(KeyboardButton::control());
+    }
+    if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
+      _input_devices[0].button_down(KeyboardButton::shift());
+    }
+    if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
+      _input_devices[0].button_down(KeyboardButton::alt());
+    }
+    if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
+      _input_devices[0].button_down(KeyboardButton::meta());
+    }
     _input_devices[0].button_down(button);
   }
 }
@@ -1241,16 +1244,19 @@ handle_keyrelease(XKeyEvent &event) {
 
   // Now get the raw unshifted button.
   ButtonHandle button = get_button(event, false);
-  if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
-    _input_devices[0].button_up(KeyboardButton::control());
-  }
-  if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
-    _input_devices[0].button_up(KeyboardButton::shift());
-  }
-  if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
-    _input_devices[0].button_up(KeyboardButton::alt());
-  }
   if (button != ButtonHandle::none()) {
+    if (button == KeyboardButton::lcontrol() || button == KeyboardButton::rcontrol()) {
+      _input_devices[0].button_up(KeyboardButton::control());
+    }
+    if (button == KeyboardButton::lshift() || button == KeyboardButton::rshift()) {
+      _input_devices[0].button_up(KeyboardButton::shift());
+    }
+    if (button == KeyboardButton::lalt() || button == KeyboardButton::ralt()) {
+      _input_devices[0].button_up(KeyboardButton::alt());
+    }
+    if (button == KeyboardButton::lmeta() || button == KeyboardButton::rmeta()) {
+      _input_devices[0].button_up(KeyboardButton::meta());
+    }
     _input_devices[0].button_up(button);
   }
 }
@@ -1636,6 +1642,8 @@ map_button(KeySym key) {
     return KeyboardButton::print_screen();
   case XK_Pause:
     return KeyboardButton::pause();
+  case XK_Menu:
+    return KeyboardButton::menu();
   case XK_Shift_L:
     return KeyboardButton::lshift();
   case XK_Shift_R:
@@ -1649,8 +1657,9 @@ map_button(KeySym key) {
   case XK_Alt_R:
     return KeyboardButton::ralt();
   case XK_Meta_L:
+    return KeyboardButton::lmeta();
   case XK_Meta_R:
-    return KeyboardButton::meta();
+    return KeyboardButton::rmeta();
   case XK_Caps_Lock:
     return KeyboardButton::caps_lock();
   case XK_Shift_Lock:

+ 8 - 0
panda/src/event/buttonEvent.cxx

@@ -55,6 +55,14 @@ output(ostream &out) const {
   case T_move:
     out << "move";
     break;
+
+  case T_raw_down:
+    out << "raw button " << _button << " down";
+    break;
+
+  case T_raw_up:
+    out << "raw button " << _button << " up";
+    break;
   }
 }
 

+ 8 - 1
panda/src/event/buttonEvent.h

@@ -81,10 +81,17 @@ public:
     // from a menu.
     T_candidate,
 
-    // T_move is used to indicate that the mouse has moved within the 
+    // T_move is used to indicate that the mouse has moved within the
     // current region. Button drag mode needs this, others may ignore
     // this event
     T_move,
+
+    // T_raw_down is usually sent together with T_down, except that
+    // this is the original, untransformed scan key sent by the keyboard.
+    // It is not altered by modifier keys and acts as if the user is
+    // using the US (qwerty) keyboard layout.
+    T_raw_down,
+    T_raw_up,
   };
 
   INLINE ButtonEvent();

+ 1 - 1
panda/src/event/pythonTask.cxx

@@ -159,7 +159,7 @@ get_args() {
     }
 
     this->ref();
-    PyObject *self = 
+    PyObject *self =
       DTool_CreatePyInstanceTyped(this, Dtool_TypedReferenceCount,
                                   true, false, get_type_index());
     PyTuple_SET_ITEM(with_task, num_args, self);

+ 9 - 3
panda/src/express/Sources.pp

@@ -6,7 +6,7 @@
   #define TARGET p3express
   #define USE_PACKAGES zlib openssl tar
   
-  #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
+  #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx $[TARGET]_ext_composite.cxx
 
   #define SOURCES \
     buffer.I buffer.h \
@@ -31,6 +31,7 @@
     memoryUsage.I memoryUsage.h \
     memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
     memoryUsagePointers.I memoryUsagePointers.h \
+    memoryUsagePointers_ext.h \
     multifile.I multifile.h \
     namable.I \
     namable.h \
@@ -51,10 +52,11 @@
     pta_int.h \
     pta_uchar.h pta_double.h pta_float.h \
     pta_stdfloat.h \
-    ramfile.I ramfile.h \
+    ramfile.I ramfile.h ramfile_ext.h \
     referenceCount.I referenceCount.h \
     subStream.I subStream.h subStreamBuf.h \
     subfileInfo.h subfileInfo.I \
+    streamReader_ext.h \
     temporaryFile.h temporaryFile.I \
     threadSafePointerTo.I threadSafePointerTo.h \
     threadSafePointerToBase.I threadSafePointerToBase.h \
@@ -70,7 +72,7 @@
     virtualFileMountSystem.h virtualFileMountSystem.I \
     virtualFileSimple.h virtualFileSimple.I \
     virtualFileSystem.h virtualFileSystem.I \
-    virtualFileSystem_ext.h virtualFileSystem_ext.cxx \
+    virtualFileSystem_ext.h \
     weakPointerCallback.I weakPointerCallback.h \
     weakPointerTo.I weakPointerTo.h \
     weakPointerToBase.I weakPointerToBase.h \
@@ -92,6 +94,7 @@
     fileReference.cxx \
     hashGeneratorBase.cxx hashVal.cxx \
     memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
+    memoryUsagePointers_ext.cxx \
     memoryUsagePointers.cxx multifile.cxx \
     namable.cxx \
     nodePointerTo.cxx \
@@ -109,8 +112,10 @@
     profileTimer.cxx \
     pta_int.cxx \
     pta_uchar.cxx pta_double.cxx pta_float.cxx \
+    ramfile_ext.cxx \
     ramfile.cxx \
     referenceCount.cxx \
+    streamReader_ext.cxx \
     subStream.cxx subStreamBuf.cxx \
     subfileInfo.cxx \
     temporaryFile.cxx \
@@ -125,6 +130,7 @@
     virtualFileMountRamdisk.cxx \
     virtualFileMountSystem.cxx \
     virtualFileSimple.cxx virtualFileSystem.cxx \
+    virtualFileSystem_ext.cxx \
     weakPointerCallback.cxx \
     weakPointerTo.cxx \
     weakPointerToBase.cxx \

+ 0 - 73
panda/src/express/memoryUsagePointers.cxx

@@ -20,20 +20,6 @@
 #include "referenceCount.h"
 #include "typedReferenceCount.h"
 
-#ifdef HAVE_PYTHON
-// Pick up a few declarations so we can create Python wrappers in
-// get_python_pointer(), below.
-
-#include "py_panda.h"  
-
-#ifndef CPPPARSER
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedObject;
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedReferenceCount;
-extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_ReferenceCount;
-#endif  // CPPPARSER
-
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsagePointers::Constructor
 //       Access: Published
@@ -151,65 +137,6 @@ get_age(int n) const {
   return _entries[n]._age;
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: MemoryUsagePointers::get_python_pointer
-//       Access: Published
-//  Description: Returns the nth object, represented as a Python
-//               object of the appropriate type.  Reference counting
-//               will be properly set on the Python object.
-//
-//               get_typed_pointer() is almost as good as this, but
-//               (a) it does not set the reference count, and (b) it
-//               does not work for objects that do not inherit from
-//               TypedObject.  This will work for any object whose
-//               type is known, which has a Python representation.
-////////////////////////////////////////////////////////////////////
-PyObject *MemoryUsagePointers::
-get_python_pointer(int n) const {
-  nassertr(n >= 0 && n < get_num_pointers(), NULL);
-  TypedObject *typed_ptr = _entries[n]._typed_ptr;
-  ReferenceCount *ref_ptr = _entries[n]._ref_ptr;
-
-  bool memory_rules = false;
-  if (ref_ptr != (ReferenceCount *)NULL) {
-    memory_rules = true;
-    ref_ptr->ref();
-  }
-
-  if (typed_ptr != (TypedObject *)NULL) {
-    return DTool_CreatePyInstanceTyped(typed_ptr, Dtool_TypedObject,
-                                       memory_rules, false, 
-                                       typed_ptr->get_type_index());
-  }
-
-  if (ref_ptr == (ReferenceCount *)NULL) {
-    return Py_BuildValue("");
-  }
-
-  TypeHandle type = _entries[n]._type;
-  if (type != TypeHandle::none()) {
-    // Use TypedReferenceCount if we have it.
-    if (type.is_derived_from(TypedReferenceCount::get_class_type())) {
-      TypedReferenceCount *typed_ref_ptr = (TypedReferenceCount *)ref_ptr;
-      
-      return DTool_CreatePyInstanceTyped(typed_ref_ptr, Dtool_TypedReferenceCount,
-                                         memory_rules, false, 
-                                         type.get_index());
-    }
-
-    // Otherwise, trust that there is a downcast path to the actual type.
-    return DTool_CreatePyInstanceTyped(ref_ptr, Dtool_ReferenceCount,
-                                       memory_rules, false, 
-                                       type.get_index());
-  }
-
-  // If worse comes to worst, just return a ReferenceCount wrapper.
-  return DTool_CreatePyInstance(ref_ptr, Dtool_ReferenceCount, 
-                                memory_rules, false);
-}
-#endif
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MemoryUsagePointers::clear
 //       Access: Published

+ 1 - 3
panda/src/express/memoryUsagePointers.h

@@ -67,9 +67,7 @@ PUBLISHED:
   string get_type_name(int n) const;
   double get_age(int n) const;
 
-#ifdef HAVE_PYTHON
-  PyObject *get_python_pointer(int n) const;
-#endif
+  EXTENSION(PyObject *get_python_pointer(int n) const);
 
   void clear();
 

+ 72 - 0
panda/src/express/memoryUsagePointers_ext.cxx

@@ -0,0 +1,72 @@
+// Filename: memoryUsagePointers_ext.cxx
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "memoryUsagePointers_ext.h"
+
+#if defined(HAVE_PYTHON) && defined(DO_MEMORY_USAGE)
+
+#ifndef CPPPARSER
+extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedObject;
+extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedReferenceCount;
+extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_ReferenceCount;
+#endif  // CPPPARSER
+
+////////////////////////////////////////////////////////////////////
+//     Function: MemoryUsagePointers::get_python_pointer
+//       Access: Published
+//  Description: Returns the nth object, represented as a Python
+//               object of the appropriate type.  Reference counting
+//               will be properly set on the Python object.
+//
+//               get_typed_pointer() is almost as good as this, but
+//               (a) it does not set the reference count, and (b) it
+//               does not work for objects that do not inherit from
+//               TypedObject.  This will work for any object whose
+//               type is known, which has a Python representation.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<MemoryUsagePointers>::
+get_python_pointer(int n) const {
+  TypedObject *typed_ptr = _this->get_typed_pointer(n);
+  ReferenceCount *ref_ptr = _this->get_pointer(n);
+
+  bool memory_rules = false;
+  if (ref_ptr != (ReferenceCount *)NULL) {
+    memory_rules = true;
+    ref_ptr->ref();
+  }
+
+  if (typed_ptr != (TypedObject *)NULL) {
+    return DTool_CreatePyInstanceTyped(typed_ptr, Dtool_TypedObject,
+                                       memory_rules, false,
+                                       typed_ptr->get_type_index());
+  }
+
+  if (ref_ptr == (ReferenceCount *)NULL) {
+    return Py_BuildValue("");
+  }
+
+  TypeHandle type = _this->get_type(n);
+  if (type != TypeHandle::none()) {
+    // Trust that there is a downcast path to the actual type.
+    return DTool_CreatePyInstanceTyped(ref_ptr, Dtool_ReferenceCount,
+                                       memory_rules, false,
+                                       type.get_index());
+  }
+
+  // If worse comes to worst, just return a ReferenceCount wrapper.
+  return DTool_CreatePyInstance(ref_ptr, Dtool_ReferenceCount,
+                                memory_rules, false);
+}
+
+#endif  // HAVE_PYTHON && DO_MEMORY_USAGE

+ 40 - 0
panda/src/express/memoryUsagePointers_ext.h

@@ -0,0 +1,40 @@
+// Filename: memoryUsagePointers_ext.h
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef MEMORYUSAGEPOINTERS_EXT_H
+#define MEMORYUSAGEPOINTERS_EXT_H
+
+#include "dtoolbase.h"
+
+#if defined(HAVE_PYTHON) && defined(DO_MEMORY_USAGE)
+
+#include "extension.h"
+#include "memoryUsagePointers.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<MemoryUsagePointers>
+// Description : This class defines the extension methods for
+//               VirtualFileSystem, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<MemoryUsagePointers> : public ExtensionBase<MemoryUsagePointers> {
+public:
+  PyObject *get_python_pointer(int n) const;
+};
+
+#endif  // HAVE_PYTHON && DO_MEMORY_USAGE
+
+#endif  // MEMORYUSAGEPOINTERS_EXT_H

+ 4 - 0
panda/src/express/p3express_ext_composite.cxx

@@ -0,0 +1,4 @@
+#include "memoryUsagePointers_ext.cxx"
+#include "ramfile_ext.cxx"
+#include "streamReader_ext.cxx"
+#include "virtualFileSystem_ext.cxx"

+ 1 - 0
panda/src/express/ramfile.h

@@ -32,6 +32,7 @@ PUBLISHED:
   INLINE size_t tell() const;
   string read(size_t length);
   string readline();
+  EXTENSION(PyObject *readlines());
 
   INLINE const string &get_data() const;
   INLINE size_t get_data_size() const;

+ 48 - 0
panda/src/express/ramfile_ext.cxx

@@ -0,0 +1,48 @@
+// Filename: ramfile_ext.cxx
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "ramfile_ext.h"
+
+#ifdef HAVE_PYTHON
+
+////////////////////////////////////////////////////////////////////
+//     Function: Ramfile::readlines
+//       Access: Published
+//  Description: Reads all the lines at once and returns a list.
+//               Also see the documentation for readline().
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<Ramfile>::
+readlines() {
+  PyObject *lst = PyList_New(0);
+  if (lst == NULL) {
+    return NULL;
+  }
+
+  string line = _this->readline();
+  while (!line.empty()) {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *py_line = PyBytes_FromStringAndSize(line.data(), line.size());
+#else
+    PyObject *py_line = PyString_FromStringAndSize(line.data(), line.size());
+#endif
+
+    PyList_Append(lst, py_line);
+    Py_DECREF(py_line);
+  }
+
+  return lst;
+}
+
+#endif
+

+ 40 - 0
panda/src/express/ramfile_ext.h

@@ -0,0 +1,40 @@
+// Filename: ramfile_ext.h
+// Created by:  rdb (10Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef RAMFILE_EXT_H
+#define RAMFILE_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "ramfile.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<Ramfile>
+// Description : This class defines the extension methods for
+//               Ramfile, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<Ramfile> : public ExtensionBase<Ramfile> {
+public:
+  BLOCKING PyObject *readlines();
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // RAMFILE_EXT_H

+ 48 - 0
panda/src/express/streamReader_ext.cxx

@@ -0,0 +1,48 @@
+// Filename: streamReader_ext.cxx
+// Created by:  rdb (09Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "streamReader_ext.h"
+
+#ifdef HAVE_PYTHON
+
+////////////////////////////////////////////////////////////////////
+//     Function: StreamReader::readlines
+//       Access: Published
+//  Description: Reads all the lines at once and returns a list.
+//               Also see the documentation for readline().
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<StreamReader>::
+readlines() {
+  PyObject *lst = PyList_New(0);
+  if (lst == NULL) {
+    return NULL;
+  }
+
+  string line = _this->readline();
+  while (!line.empty()) {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *py_line = PyBytes_FromStringAndSize(line.data(), line.size());
+#else
+    PyObject *py_line = PyString_FromStringAndSize(line.data(), line.size());
+#endif
+
+    PyList_Append(lst, py_line);
+    Py_DECREF(py_line);
+  }
+
+  return lst;
+}
+
+#endif
+

+ 40 - 0
panda/src/express/streamReader_ext.h

@@ -0,0 +1,40 @@
+// Filename: streamReader_ext.h
+// Created by:  rdb (09Dec13)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef STREAMREADER_EXT_H
+#define STREAMREADER_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "streamReader.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<StreamReader>
+// Description : This class defines the extension methods for
+//               StreamReader, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<StreamReader> : public ExtensionBase<StreamReader> {
+public:
+  BLOCKING PyObject *readlines();
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // STREAMREADER_EXT_H

+ 2 - 0
panda/src/express/virtualFileSystem.cxx

@@ -514,6 +514,7 @@ make_directory(const Filename &filename) {
   _lock.acquire();
   PT(VirtualFile) result = do_get_file(filename, OF_make_directory);
   _lock.release();
+  nassertr_always(result != NULL, false);
   return result->is_directory();
 }
 
@@ -542,6 +543,7 @@ make_directory_full(const Filename &filename) {
   // Now make the last one, and check the return value.
   PT(VirtualFile) result = do_get_file(filename, OF_make_directory);
   _lock.release();
+  nassertr_always(result != NULL, false);
   return result->is_directory();
 }
 

+ 1 - 1
panda/src/express/virtualFileSystem_ext.cxx

@@ -79,4 +79,4 @@ write_file(const Filename &filename, PyObject *data, bool auto_wrap) {
   return PyBool_FromLong(result);
 }
 
-#endif  // HAVE_PYTHOS
+#endif  // HAVE_PYTHON

+ 10 - 0
panda/src/gles2gsg/gles2gsg.h

@@ -80,12 +80,22 @@ typedef char GLchar;
 #define GL_DEPTH_ATTACHMENT_EXT GL_DEPTH_ATTACHMENT
 #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
 #define GL_STENCIL_ATTACHMENT_EXT GL_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES
+#define GL_DEPTH_STENCIL_EXT GL_DEPTH_STENCIL_OES
+#define GL_UNSIGNED_INT_24_8_EXT GL_UNSIGNED_INT_24_8_OES
+#define GL_DEPTH24_STENCIL8_EXT GL_DEPTH24_STENCIL8_OES
 #define GL_DEPTH_COMPONENT24 GL_DEPTH_COMPONENT24_OES
 #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES
 #define GL_TEXTURE_3D GL_TEXTURE_3D_OES
 #define GL_MAX_3D_TEXTURE_SIZE GL_MAX_3D_TEXTURE_SIZE_OES
 #define GL_SAMPLER_3D GL_SAMPLER_3D_OES
 #define GL_BGRA GL_BGRA_EXT
+#define GL_RED GL_RED_EXT
+#define GL_RG GL_RG_EXT
+#define GL_R16F GL_R16F_EXT
+#define GL_RG16F GL_RG16F_EXT
+#define GL_RGB16F GL_RGB16F_EXT
+#define GL_RGBA16F GL_RGBA16F_EXT
 
 #undef SUPPORT_IMMEDIATE_MODE
 #define APIENTRY

+ 75 - 100
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -559,15 +559,10 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
   }
 
   if (tex) {
-    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
-    if (target == GL_TEXTURE_CUBE_MAP) {
-      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
-    }
-
     // Bind the texture to the slot.
     tex->set_x_size(_rb_size_x);
     tex->set_y_size(_rb_size_y);
-    if (target != GL_TEXTURE_CUBE_MAP && _rb_size_z > 1) {
+    if (tex->get_texture_type() != Texture::TT_cube_map && _rb_size_z > 1) {
       tex->set_z_size(_rb_size_z);
     }
     tex->set_pad_size(_rb_size_x - _x_size, _rb_size_y - _y_size);
@@ -617,85 +612,41 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
       }
     }
 
-    // Create the OpenGL texture object.
-    TextureContext *tc = tex->prepare_now(0, glgsg->get_prepared_objects(), glgsg);
-    nassertv(tc != (TextureContext *)NULL);
-    CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-    glgsg->update_texture(tc, true);
+#ifndef OPENGLES
+    GLenum target = glgsg->get_texture_target(tex->get_texture_type());
+    if (target == GL_TEXTURE_CUBE_MAP) {
+      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+    }
+#endif
 
     if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) {
       GLCAT.debug() << "Binding texture " << *tex << " to depth attachment.\n";
 
-#ifndef OPENGLES
-      GLclampf priority = 1.0f;
-      glPrioritizeTextures(1, &gtc->_index, &priority);
-#endif
-      if (_rb_size_z == 1) {
-        if (target == GL_TEXTURE_3D) {
-          glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-                                         target, gtc->_index, 0, layer);
-        } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-          glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-                                            gtc->_index, 0, layer);
-        } else {
-          glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-                                         target, gtc->_index, 0);
-        }
-      } else {
-        glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
-                                     gtc->_index, 0);
-      }
+      attach_tex(layer, 0, tex, GL_DEPTH_ATTACHMENT_EXT);
 
+#ifndef OPENGLES
       GLint depth_size = 0;
       GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_DEPTH_SIZE, &depth_size);
       _fb_properties.set_depth_bits(depth_size);
+#endif
 
       if (slot == RTP_depth_stencil) {
         GLCAT.debug() << "Binding texture " << *tex << " to stencil attachment.\n";
-        if (_rb_size_z == 1) {
-          if (target == GL_TEXTURE_3D) {
-            glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
-                                           target, gtc->_index, 0, layer);
-          } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-            glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
-                                              gtc->_index, 0, layer);
-          } else {
-            glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
-                                           target, gtc->_index, 0);
-          }
-        } else {
-          glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
-                                       gtc->_index, 0);
-        }
 
+        attach_tex(layer, 0, tex, GL_STENCIL_ATTACHMENT_EXT);
+
+#ifndef OPENGLES
         GLint stencil_size = 0;
         GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_STENCIL_SIZE, &stencil_size);
         _fb_properties.set_stencil_bits(stencil_size);
+#endif
       }
 
     } else {
       GLCAT.debug() << "Binding texture " << *tex << " to color attachment.\n";
 
-#ifndef OPENGLES
-      GLclampf priority = 1.0f;
-      glPrioritizeTextures(1, &gtc->_index, &priority);
-#endif
-      glgsg->update_texture(tc, true);
-      if (_rb_size_z == 1) {
-        if (target == GL_TEXTURE_3D) {
-          glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, attachpoint,
-                                         target, gtc->_index, 0, layer);
-        } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-          glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint,
-                                            gtc->_index, 0, layer);
-        } else {
-          glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
-                                         target, gtc->_index, 0);
-        }
-      } else {
-        glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachpoint,
-                                     gtc->_index, 0);
-      }
+      attach_tex(layer, 0, tex, attachpoint);
+
 #ifndef OPENGLES
       if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) {
         GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0;
@@ -749,16 +700,16 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
           gl_format = GL_RGB10_EXT;
         }
       } else if (_fb_properties.get_color_bits() == 0) {
-        gl_format = GL_ALPHA8_OES;
+        gl_format = GL_ALPHA8_EXT;
       } else if (_fb_properties.get_color_bits() <= 12
               && _fb_properties.get_alpha_bits() <= 4) {
         gl_format = GL_RGBA4_OES;
       } else if (_fb_properties.get_color_bits() <= 15
               && _fb_properties.get_alpha_bits() == 1) {
-        gl_format = GL_RGB5_A1_EXT;
+        gl_format = GL_RGB5_A1_OES;
       } else if (_fb_properties.get_color_bits() <= 30
               && _fb_properties.get_alpha_bits() <= 2) {
-        gl_format = GL_RGB10_A2_OES;
+        gl_format = GL_RGB10_A2_EXT;
       } else {
         gl_format = GL_RGBA8_OES;
       }
@@ -1000,6 +951,61 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
   glgsg->report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: glGraphicsBuffer::attach_tex
+//       Access: Private
+//  Description: This function attaches the given texture to the
+//               given attachment point.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsBuffer)::
+attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
+  CLP(GraphicsStateGuardian) *glgsg;
+  DCAST_INTO_V(glgsg, _gsg);
+
+  // Create the OpenGL texture object.
+  TextureContext *tc = attach->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
+  nassertv(tc != (TextureContext *)NULL);
+  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+  glgsg->update_texture(tc, true);
+
+#ifndef OPENGLES
+  GLclampf priority = 1.0f;
+  glPrioritizeTextures(1, &gtc->_index, &priority);
+#endif
+
+#ifndef OPENGLES
+  if (_rb_size_z != 1) {
+    // Bind all of the layers of the texture.
+    glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachpoint,
+                                 gtc->_index, 0);
+    return;
+  }
+#endif
+
+  GLenum target = glgsg->get_texture_target(attach->get_texture_type());
+  if (target == GL_TEXTURE_CUBE_MAP) {
+    target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
+  } 
+
+  switch (target) {
+#ifndef OPENGLES_1
+  case GL_TEXTURE_3D:
+    glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, attachpoint,
+                                   target, gtc->_index, 0, layer);
+    break;
+#endif
+#ifndef OPENGLES
+  case GL_TEXTURE_2D_ARRAY_EXT:
+    glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint,
+                                      gtc->_index, 0, layer);
+    break;
+#endif
+  default:
+    glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint,
+                                   target, gtc->_index, 0);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: glGraphicsBuffer::generate_mipmaps
 //       Access: Private
@@ -1129,44 +1135,13 @@ select_target_tex_page(int page, int view) {
         tex->set_num_views(view + 1);
       }
 
-      GLenum target = glgsg->get_texture_target(tex->get_texture_type());
-      if (target == GL_TEXTURE_CUBE_MAP) {
-        target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _bound_tex_page;
-      }
-
-      // Create the OpenGL texture object.
-      TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
-      nassertv(tc != (TextureContext *)NULL);
-      CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-      glgsg->update_texture(tc, true);
-
       if (GLCAT.is_spam()) {
         GLCAT.spam()
           << "Binding texture " << *tex
           << " view " << view << " to color attachment.\n";
       }
 
-#ifndef OPENGLES
-      GLclampf priority = 1.0f;
-      glPrioritizeTextures(1, &gtc->_index, &priority);
-#endif
-      glgsg->update_texture(tc, true);
-
-      if (_rb_size_z == 1) {
-        if (target == GL_TEXTURE_3D) {
-          glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                         target, gtc->_index, 0, _bound_tex_page);
-        } else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
-          glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                            gtc->_index, 0, _bound_tex_page);
-        } else {
-          glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                         target, gtc->_index, 0);
-        }
-      } else {
-        glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                     gtc->_index, 0);
-      }
+      attach_tex(_bound_tex_page, view, tex, GL_COLOR_ATTACHMENT0_EXT);
 
       report_my_gl_errors();
     }

+ 1 - 0
panda/src/glstuff/glGraphicsBuffer_src.h

@@ -98,6 +98,7 @@ private:
                  RenderTexturePlane plane, GLenum attachpoint);
   void bind_slot_multisample(bool rb_resize, Texture **attach,
                  RenderTexturePlane plane, GLenum attachpoint);
+  void attach_tex(int layer, int view, Texture *attach, GLenum attachpoint);
   bool check_fbo();
   void generate_mipmaps();
   void rebuild_bitplanes();

+ 19 - 7
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1106,7 +1106,7 @@ reset() {
   _glGetShaderInfoLog = glGetShaderInfoLog;
   _glGetUniformLocation = glGetUniformLocation;
   _glLinkProgram = glLinkProgram;
-  _glShaderSource = glShaderSource;
+  _glShaderSource = (PFNGLSHADERSOURCEPROC_P) glShaderSource;
   _glUseProgram = glUseProgram;
   _glUniform4f = glUniform4f;
   _glUniform1i = glUniform1i;
@@ -6405,8 +6405,10 @@ get_external_image_format(Texture *tex) const {
 #endif
   case Texture::F_alpha:
     return GL_ALPHA;
+#ifndef OPENGLES_1
   case Texture::F_rg16:
     return GL_RG;
+#endif
   case Texture::F_rgb:
   case Texture::F_rgb5:
   case Texture::F_rgb8:
@@ -6681,8 +6683,10 @@ get_internal_image_format(Texture *tex) const {
     return GL_RGBA8_OES;
   case Texture::F_rgba12:
     return GL_RGBA;
+#ifndef OPENGLES_1
   case Texture::F_rgba16:
     return GL_RGBA16F_EXT;
+#endif  // OPENGLES_1
   case Texture::F_rgba32:
     return GL_RGBA32F_EXT;
 #else
@@ -6733,12 +6737,12 @@ get_internal_image_format(Texture *tex) const {
     return GL_R3_G3_B2;
 #endif
 
-#ifdef OPENGLES
+#if defined(OPENGLES_2)
   case Texture::F_r16:
     return GL_R16F_EXT;
   case Texture::F_rg16:
     return GL_RG16F_EXT;
-#else
+#elif !defined(OPENGLES_1)
   case Texture::F_r16:
     if (tex->get_component_type() == Texture::T_float) {
       return GL_R16F;
@@ -6756,10 +6760,12 @@ get_internal_image_format(Texture *tex) const {
   case Texture::F_alpha:
     return GL_ALPHA;
 
+#ifndef OPENGLES_1
   case Texture::F_red:
   case Texture::F_green:
   case Texture::F_blue:
     return GL_RED;
+#endif
 
   case Texture::F_luminance:
     return GL_LUMINANCE;
@@ -9333,9 +9339,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
           break;
         case GL_TEXTURE_2D_ARRAY:
 #endif
+#ifndef OPENGLES_1
         case GL_TEXTURE_3D:
           _glTexImage3D(page_target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL);
           break;
+#endif
         default:
           GLP(TexImage2D)(page_target, 0, internal_format, width, height, 0, external_format, component_type, NULL);
           break;
@@ -9817,10 +9825,12 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     type = Texture::T_unsigned_short;
     format = Texture::F_depth_component;
     break;
+#ifndef OPENGLES
   case GL_DEPTH_COMPONENT32F:
     type = Texture::T_float;
     format = Texture::F_depth_component;
     break;
+#endif
   case GL_DEPTH_STENCIL_EXT:
   case GL_DEPTH24_STENCIL8_EXT:
     type = Texture::T_unsigned_int_24_8;
@@ -9848,10 +9858,6 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     format = Texture::F_rgba12;
     break;
 #endif
-  case GL_RGBA16F:
-    type = Texture::T_float;
-    format = Texture::F_rgba16;
-    break;
 
   case GL_RGB:
   case 3:
@@ -9877,6 +9883,11 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     break;
 #endif
 
+#ifndef OPENGLES_1
+  case GL_RGBA16F:
+    type = Texture::T_float;
+    format = Texture::F_rgba16;
+    break;
   case GL_RGB16F:
     type = Texture::T_float;
     format = Texture::F_rgb16;
@@ -9889,6 +9900,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
     type = Texture::T_float;
     format = Texture::F_r16;
     break;
+#endif
 
 #ifndef OPENGLES
   case GL_RGB16:

+ 91 - 67
panda/src/glstuff/glShaderContext_src.cxx

@@ -71,14 +71,13 @@ TypeHandle CLP(ShaderContext)::_type_handle;
 bool CLP(ShaderContext)::
 parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objShader) {
     Shader::ShaderArgInfo p;
-  
     p._id = arg_id;
-    
+
     string basename(arg_id._name);
     // Split it at the underscores.
     vector_string pieces;
     tokenize(basename, pieces, "_");
-    
+
     if (pieces[0] == "mstrans") {
         pieces[0] = "trans";
         pieces.push_back("to");
@@ -119,9 +118,9 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
         pieces.push_back("to");
         pieces.push_back("clip");
     }
-    
-    if ((pieces[0] == "mat")||(pieces[0] == "inv")||
-      (pieces[0] == "tps")||(pieces[0] == "itp")) {
+
+    if ((pieces[0] == "mat") || (pieces[0] == "inv") ||
+        (pieces[0] == "tps") || (pieces[0] == "itp")) {
         if (!objShader->cp_errchk_parameter_words(p, 2)) {
             return false;
         }
@@ -138,33 +137,33 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
             objShader->cp_report_error(p,"unrecognized matrix name");
             return false;
         }
-        if (trans=="mat") {
+        if (trans == "mat") {
             pieces[0] = "trans";
-        } else if (trans=="inv") {
+        } else if (trans == "inv") {
             string t = pieces[1];
             pieces[1] = pieces[3];
             pieces[3] = t;
-        } else if (trans=="tps") {
+        } else if (trans == "tps") {
             pieces[0] = "tpose";
-        } else if (trans=="itp") {
+        } else if (trans == "itp") {
             string t = pieces[1];
             pieces[1] = pieces[3];
             pieces[3] = t;
             pieces[0] = "tpose";
-            }
+        }
     }
   // Implement the transform-matrix generator.
 
-    if ((pieces[0]=="trans")||
-        (pieces[0]=="tpose")||
-        (pieces[0]=="row0")||
-        (pieces[0]=="row1")||
-        (pieces[0]=="row2")||
-        (pieces[0]=="row3")||
-        (pieces[0]=="col0")||
-        (pieces[0]=="col1")||
-        (pieces[0]=="col2")||
-        (pieces[0]=="col3")) {
+    if ((pieces[0] == "trans") ||
+        (pieces[0] == "tpose") ||
+        (pieces[0] == "row0") ||
+        (pieces[0] == "row1") ||
+        (pieces[0] == "row2") ||
+        (pieces[0] == "row3") ||
+        (pieces[0] == "col0") ||
+        (pieces[0] == "col1") ||
+        (pieces[0] == "col2") ||
+        (pieces[0] == "col3")) {
 
         Shader::ShaderMatSpec bind;
         bind._id = arg_id;
@@ -174,27 +173,26 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *objSha
         pieces.push_back("");
 
         // Decide whether this is a matrix or vector.
-        if      (pieces[0]=="trans")   bind._piece = Shader::SMP_whole;
-        else if (pieces[0]=="tpose")   bind._piece = Shader::SMP_transpose;
-        else if (pieces[0]=="row0")    bind._piece = Shader::SMP_row0;
-        else if (pieces[0]=="row1")    bind._piece = Shader::SMP_row1;
-        else if (pieces[0]=="row2")    bind._piece = Shader::SMP_row2;
-        else if (pieces[0]=="row3")    bind._piece = Shader::SMP_row3;
-        else if (pieces[0]=="col0")    bind._piece = Shader::SMP_col0;
-        else if (pieces[0]=="col1")    bind._piece = Shader::SMP_col1;
-        else if (pieces[0]=="col2")    bind._piece = Shader::SMP_col2;
-        else if (pieces[0]=="col3")    bind._piece = Shader::SMP_col3;
+        if      (pieces[0] == "trans") bind._piece = Shader::SMP_whole;
+        else if (pieces[0] == "tpose") bind._piece = Shader::SMP_transpose;
+        else if (pieces[0] == "row0")  bind._piece = Shader::SMP_row0;
+        else if (pieces[0] == "row1")  bind._piece = Shader::SMP_row1;
+        else if (pieces[0] == "row2")  bind._piece = Shader::SMP_row2;
+        else if (pieces[0] == "row3")  bind._piece = Shader::SMP_row3;
+        else if (pieces[0] == "col0")  bind._piece = Shader::SMP_col0;
+        else if (pieces[0] == "col1")  bind._piece = Shader::SMP_col1;
+        else if (pieces[0] == "col2")  bind._piece = Shader::SMP_col2;
+        else if (pieces[0] == "col3")  bind._piece = Shader::SMP_col3;
 
         if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, true)) {
           return false;
         }
         if (!objShader->cp_parse_delimiter(p, pieces, next)) {
           return false;
-        }    
+        }
         if (!objShader->cp_parse_coord_sys(p, pieces, next, bind, false)) {
           return false;
         }
-        
         if (!objShader->cp_parse_eol(p, pieces, next)) {
           return false;
         }
@@ -223,51 +221,58 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
 
 #if defined(HAVE_CG) && !defined(OPENGLES)
   _cg_context = 0;
+  _cg_vprofile = CG_PROFILE_UNKNOWN;
+  _cg_fprofile = CG_PROFILE_UNKNOWN;
+  _cg_gprofile = CG_PROFILE_UNKNOWN;
   if (s->get_language() == Shader::SL_Cg) {
-    
     // Ask the shader to compile itself for us and 
     // to give us the resulting Cg program objects.
 
     if (!s->cg_compile_for(gsg->_shader_caps,
                            _cg_context,
                            _cg_vprogram,
-                           _cg_fprogram, 
+                           _cg_fprogram,
                            _cg_gprogram,
                            _cg_parameter_map)) {
       return;
     }
-    
+
     // Load the program.
-    
     if (_cg_vprogram != 0) {
+      _cg_vprofile = cgGetProgramProfile(_cg_vprogram);
       cgGLLoadProgram(_cg_vprogram);
       CGerror verror = cgGetError();
       if (verror != CG_NO_ERROR) {
-        const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
-        GLCAT.error() << "Could not load Cg vertex program:" << s->get_filename(Shader::ST_vertex) << " (" << 
-          cgGetProfileString(cgGetProgramProfile(_cg_vprogram)) << " " << str << ")\n";
+        const char *str = cgGetErrorString(verror);
+        GLCAT.error()
+          << "Could not load Cg vertex program: " << s->get_filename(Shader::ST_vertex)
+          << " (" << cgGetProfileString(_cg_vprofile) << " " << str << ")\n";
         release_resources(gsg);
       }
     }
 
     if (_cg_fprogram != 0) {
+      _cg_fprofile = cgGetProgramProfile(_cg_fprogram);
       cgGLLoadProgram(_cg_fprogram);
       CGerror ferror = cgGetError();
       if (ferror != CG_NO_ERROR) {
-        const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
-        GLCAT.error() << "Could not load Cg fragment program:" << s->get_filename(Shader::ST_fragment) << " (" << 
-          cgGetProfileString(cgGetProgramProfile(_cg_fprogram)) << " " << str << ")\n";
+        const char *str = cgGetErrorString(ferror);
+        GLCAT.error()
+          << "Could not load Cg fragment program: " << s->get_filename(Shader::ST_fragment)
+          << " (" << cgGetProfileString(_cg_fprofile) << " " << str << ")\n";
         release_resources(gsg);
       }
     }
 
     if (_cg_gprogram != 0) {
+      _cg_gprofile = cgGetProgramProfile(_cg_gprogram);
       cgGLLoadProgram(_cg_gprogram);
       CGerror gerror = cgGetError();
       if (gerror != CG_NO_ERROR) {
-        const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
-        GLCAT.error() << "Could not load Cg geometry program:" << s->get_filename(Shader::ST_geometry) << " (" << 
-          cgGetProfileString(cgGetProgramProfile(_cg_gprogram)) << " " << str << ")\n";
+        const char *str = cgGetErrorString(gerror);
+        GLCAT.error()
+          << "Could not load Cg geometry program: " << s->get_filename(Shader::ST_geometry)
+          << " (" << cgGetProfileString(_cg_gprofile) << " " << str << ")\n";
         release_resources(gsg);
       }
     }
@@ -338,7 +343,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
               }
               bind._arg[0] = NULL;
               bind._arg[1] = NULL;
-              
+
               if (matrix_name == "ModelViewProjectionMatrix") {
                 bind._func = Shader::SMF_compose;
                 if (inverse) {
@@ -418,15 +423,14 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
             // them as well, to increase compatibility.
             // Other inputs we may support in the future:
             // int osg_FrameNumber
-            // float osg_FrameTime
-            // float osg_DeltaFrameTime
+
+            Shader::ShaderMatSpec bind;
+            bind._id = arg_id;
+            bind._arg[0] = NULL;
+            bind._arg[1] = NULL;
 
             if (param_name == "osg_ViewMatrix") {
-              Shader::ShaderMatSpec bind;
-              bind._id = arg_id;
               bind._piece = Shader::SMP_whole;
-              bind._arg[0] = NULL;
-              bind._arg[1] = NULL;
               bind._func = Shader::SMF_first;
               bind._part[0] = Shader::SMO_world_to_view;
               bind._part[1] = Shader::SMO_identity;
@@ -436,11 +440,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
               continue;
 
             } else if (param_name == "osg_InverseViewMatrix") {
-              Shader::ShaderMatSpec bind;
-              bind._id = arg_id;
               bind._piece = Shader::SMP_whole;
-              bind._arg[0] = NULL;
-              bind._arg[1] = NULL;
               bind._func = Shader::SMF_first;
               bind._part[0] = Shader::SMO_view_to_world;
               bind._part[1] = Shader::SMO_identity;
@@ -448,6 +448,26 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
               bind._dep[1] = Shader::SSD_NONE;
               s->_mat_spec.push_back(bind);
               continue;
+
+            } else if (param_name == "osg_FrameTime") {
+              bind._piece = Shader::SMP_row3x1;
+              bind._func = Shader::SMF_first;
+              bind._part[0] = Shader::SMO_frame_time;
+              bind._part[1] = Shader::SMO_identity;
+              bind._dep[0] = Shader::SSD_general;
+              bind._dep[1] = Shader::SSD_NONE;
+              s->_mat_spec.push_back(bind);
+              continue;
+
+            } else if (param_name == "osg_DeltaFrameTime") {
+              bind._piece = Shader::SMP_row3x1;
+              bind._func = Shader::SMF_first;
+              bind._part[0] = Shader::SMO_frame_delta;
+              bind._part[1] = Shader::SMO_identity;
+              bind._dep[0] = Shader::SSD_general;
+              bind._dep[1] = Shader::SSD_NONE;
+              s->_mat_spec.push_back(bind);
+              continue;
             }
           }
 
@@ -455,7 +475,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
           if (parse_and_set_short_hand_shader_vars(arg_id, s)) {
             continue;
           }
-          
+
           if (param_size == 1) {
             switch (param_type) {
 #ifndef OPENGLES
@@ -706,7 +726,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
       }
     }
   }
-  
+
   gsg->report_my_gl_errors();
 }
 
@@ -819,15 +839,15 @@ bind(GSG *gsg, bool reissue_parameters) {
   if (_cg_context != 0) {
     // Bind the shaders.
     if (_cg_vprogram != 0) {
-      cgGLEnableProfile(cgGetProgramProfile(_cg_vprogram));
+      cgGLEnableProfile(_cg_vprofile);
       cgGLBindProgram(_cg_vprogram);
     }
     if (_cg_fprogram != 0) {
-      cgGLEnableProfile(cgGetProgramProfile(_cg_fprogram));
+      cgGLEnableProfile(_cg_fprofile);
       cgGLBindProgram(_cg_fprogram);
     }
     if (_cg_gprogram != 0) {
-      cgGLEnableProfile(cgGetProgramProfile(_cg_gprogram));
+      cgGLEnableProfile(_cg_gprofile);
       cgGLBindProgram(_cg_gprogram);
     }
 
@@ -850,19 +870,22 @@ unbind(GSG *gsg) {
 #if defined(HAVE_CG) && !defined(OPENGLES)
   if (_cg_context != 0) {
     if (_cg_vprogram != 0) {
-      cgGLDisableProfile(cgGetProgramProfile(_cg_vprogram));
+      cgGLUnbindProgram(_cg_vprofile);
+      cgGLDisableProfile(_cg_vprofile);
     }
     if (_cg_fprogram != 0) {
-      cgGLDisableProfile(cgGetProgramProfile(_cg_fprogram));
+      cgGLUnbindProgram(_cg_fprofile);
+      cgGLDisableProfile(_cg_fprofile);
     }
     if (_cg_gprogram != 0) {
-      cgGLDisableProfile(cgGetProgramProfile(_cg_gprogram));
+      cgGLUnbindProgram(_cg_gprofile);
+      cgGLDisableProfile(_cg_gprofile);
     }
 
     cg_report_errors();
   }
 #endif
-  
+
   if (_shader->get_language() == Shader::SL_GLSL) {
     gsg->_glUseProgram(0);
   }
@@ -1162,12 +1185,13 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
         }
       }
 #endif
-      
+
       InternalName *name = _shader->_var_spec[i]._name;
       int texslot = _shader->_var_spec[i]._append_uv;
       if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) {
         TextureStage *stage = gsg->_state_texture->get_on_stage(texslot);
         InternalName *texname = stage->get_texcoord_name();
+
         if (name == InternalName::get_texcoord()) {
           name = texname;
         } else if (texname != InternalName::get_texcoord()) {

+ 8 - 1
panda/src/glstuff/glShaderContext_src.h

@@ -21,6 +21,10 @@
 #include "shaderContext.h"
 #include "deletedChain.h"
 
+#if defined(HAVE_CG) && !defined(OPENGLES)
+#include <Cg/cg.h>
+#endif
+
 class CLP(GraphicsStateGuardian);
 
 ////////////////////////////////////////////////////////////////////
@@ -57,10 +61,13 @@ private:
   CGprogram _cg_vprogram;
   CGprogram _cg_fprogram;
   CGprogram _cg_gprogram;
+  CGprofile _cg_vprofile;
+  CGprofile _cg_fprofile;
+  CGprofile _cg_gprofile;
 
   pvector <CGparameter> _cg_parameter_map;
 #endif
-  
+
   GLuint _glsl_program;
   GLuint _glsl_vshader;
   GLuint _glsl_fshader;

+ 19 - 0
panda/src/gobj/internalName.cxx

@@ -154,6 +154,25 @@ get_name() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::join
+//       Access: Published
+//  Description: Like get_name, but uses a custom separator instead
+//               of ".".
+////////////////////////////////////////////////////////////////////
+string InternalName::
+join(const string &sep) const {
+  if (_parent == get_root()) {
+    return _basename;
+
+  } else if (_parent == (InternalName *)NULL) {
+    return string();
+
+  } else {
+    return _parent->join(sep) + sep + _basename;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::find_ancestor
 //       Access: Published

+ 1 - 0
panda/src/gobj/internalName.h

@@ -53,6 +53,7 @@ PUBLISHED:
 
   INLINE InternalName *get_parent() const;
   string get_name() const;
+  string join(const string &sep) const;
   INLINE const string &get_basename() const;
 
   int find_ancestor(const string &basename) const;

+ 47 - 28
panda/src/gobj/shader.cxx

@@ -414,23 +414,23 @@ cp_dependency(ShaderMatInput inp) {
       (inp == SMO_view_to_model)) {
     dep |= SSD_transform;
   }
-  if ((inp == SMO_texpad_x)||
-      (inp == SMO_texpix_x)||
-      (inp == SMO_alight_x)||
-      (inp == SMO_dlight_x)||
-      (inp == SMO_plight_x)||
-      (inp == SMO_slight_x)||
-      (inp == SMO_satten_x)||
-      (inp == SMO_mat_constant_x)||
-      (inp == SMO_vec_constant_x)||
-      (inp == SMO_clipplane_x)||
-      (inp == SMO_view_x_to_view)||
-      (inp == SMO_view_to_view_x)||
-      (inp == SMO_apiview_x_to_view)||
-      (inp == SMO_view_to_apiview_x)||
-      (inp == SMO_clip_x_to_view)||
-      (inp == SMO_view_to_clip_x)||
-      (inp == SMO_apiclip_x_to_view)||
+  if ((inp == SMO_texpad_x) ||
+      (inp == SMO_texpix_x) ||
+      (inp == SMO_alight_x) ||
+      (inp == SMO_dlight_x) ||
+      (inp == SMO_plight_x) ||
+      (inp == SMO_slight_x) ||
+      (inp == SMO_satten_x) ||
+      (inp == SMO_mat_constant_x) ||
+      (inp == SMO_vec_constant_x) ||
+      (inp == SMO_clipplane_x) ||
+      (inp == SMO_view_x_to_view) ||
+      (inp == SMO_view_to_view_x) ||
+      (inp == SMO_apiview_x_to_view) ||
+      (inp == SMO_view_to_apiview_x) ||
+      (inp == SMO_clip_x_to_view) ||
+      (inp == SMO_view_to_clip_x) ||
+      (inp == SMO_apiclip_x_to_view) ||
       (inp == SMO_view_to_apiclip_x)) {
     dep |= SSD_shaderinputs;
   }
@@ -588,36 +588,45 @@ compile_parameter(const ShaderArgId        &arg_id,
     }
     ShaderVarSpec bind;
     bind._id = arg_id;
+    bind._append_uv = -1;
+
     if (pieces.size() == 2) {
-      if (pieces[1]=="position") {
+      if (pieces[1] == "position") {
         bind._name = InternalName::get_vertex();
         bind._append_uv = -1;
         _var_spec.push_back(bind);
         return true;
       }
-      if (pieces[1].substr(0,8)=="texcoord") {
+      if (pieces[1].substr(0, 8) == "texcoord") {
         bind._name = InternalName::get_texcoord();
-        bind._append_uv = atoi(pieces[1].c_str()+8);
+        if (pieces[1].size() > 8) {
+          bind._append_uv = atoi(pieces[1].c_str() + 8);
+        }
         _var_spec.push_back(bind);
         return true;
       }
-      if (pieces[1].substr(0,7)=="tangent") {
+      if (pieces[1].substr(0, 7) == "tangent") {
         bind._name = InternalName::get_tangent();
-        bind._append_uv = atoi(pieces[1].c_str()+7);
+        if (pieces[1].size() > 7) {
+          bind._append_uv = atoi(pieces[1].c_str() + 7);
+        }
         _var_spec.push_back(bind);
         return true;
       }
-      if (pieces[1].substr(0,8)=="binormal") {
+      if (pieces[1].substr(0, 8) == "binormal") {
         bind._name = InternalName::get_binormal();
-        bind._append_uv = atoi(pieces[1].c_str()+8);
+        if (pieces[1].size() > 8) {
+          bind._append_uv = atoi(pieces[1].c_str() + 8);
+        }
         _var_spec.push_back(bind);
         return true;
       }
     }
+
     bind._name = InternalName::get_root();
-    bind._append_uv = -1;
-    for (int i=1; i<(int)(pieces.size()-0); i++)
+    for (int i = 1; i < pieces.size(); ++i) {
       bind._name = bind._name->append(pieces[i]);
+    }
     _var_spec.push_back(bind);
     return true;
   }
@@ -1008,7 +1017,7 @@ compile_parameter(const ShaderArgId        &arg_id,
   // Keywords to access unusual parameters.
 
   if (pieces[0] == "sys") {
-    if ((!cp_errchk_parameter_words(p,2)) ||
+    if ((!cp_errchk_parameter_words(p, 2)) ||
         (!cp_errchk_parameter_in(p)) ||
         (!cp_errchk_parameter_uniform(p))) {
       return false;
@@ -1025,14 +1034,24 @@ compile_parameter(const ShaderArgId        &arg_id,
       }
       bind._part[0] = SMO_pixel_size;
       bind._arg[0] = NULL;
+
     } else if (pieces[1] == "windowsize") {
       if (!cp_errchk_parameter_float(p, 2, 2)) {
         return false;
       }
       bind._part[0] = SMO_window_size;
       bind._arg[0] = NULL;
+
+    } else if (pieces[1] == "time") {
+      if (!cp_errchk_parameter_float(p, 1, 1)) {
+        return false;
+      }
+      bind._piece = SMP_row3x1;
+      bind._part[0] = SMO_frame_time;
+      bind._arg[0] = NULL;
+
     } else {
-      cp_report_error(p,"unknown system parameter");
+      cp_report_error(p, "unknown system parameter");
       return false;
     }
 

+ 71 - 67
panda/src/gobj/shader.h

@@ -31,7 +31,7 @@
 #include "pta_LVecBase2.h"
 
 #ifdef HAVE_CG
-// I don't want to include the Cg header file into panda as a 
+// I don't want to include the Cg header file into panda as a
 // whole.  Instead, I'll just excerpt some opaque declarations.
 typedef struct _CGcontext   *CGcontext;
 typedef struct _CGprogram   *CGprogram;
@@ -41,8 +41,8 @@ typedef struct _CGparameter *CGparameter;
 ////////////////////////////////////////////////////////////////////
 //       Class : Shader
 //      Summary: The Shader class is meant to select the Shader Language,
-//               select the available profile, compile the shader, and 
-//               finally compile and store the shader parameters  
+//               select the available profile, compile the shader, and
+//               finally compile and store the shader parameters
 //               in the appropriate structure.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
@@ -116,11 +116,11 @@ public:
     SMO_pixel_size,
     SMO_texpad_x,
     SMO_texpix_x,
-    
+
     SMO_attr_material,
     SMO_attr_color,
     SMO_attr_colorscale,
-    
+
     SMO_alight_x,
     SMO_dlight_x,
     SMO_plight_x,
@@ -129,7 +129,7 @@ public:
     SMO_texmat_x,
     SMO_plane_x,
     SMO_clipplane_x,
-    
+
     SMO_mat_constant_x,
     SMO_vec_constant_x,
 
@@ -147,7 +147,7 @@ public:
 
     SMO_apiclip_to_view,
     SMO_view_to_apiclip,
-    
+
     SMO_view_x_to_view,
     SMO_view_to_view_x,
 
@@ -162,11 +162,15 @@ public:
 
     SMO_attr_fog,
     SMO_attr_fogcolor,
-    
+
+    SMO_frame_number,
+    SMO_frame_time,
+    SMO_frame_delta,
+
     SMO_INVALID
   };
-  
-  enum ShaderArgClass { 
+
+  enum ShaderArgClass {
     SAC_scalar,
     SAC_vector,
     SAC_matrix,
@@ -174,28 +178,28 @@ public:
     SAC_array,
     SAC_unknown,
   };
-  
-  enum ShaderArgType { 
-    SAT_scalar,     
-    SAT_vec1,       
-    SAT_vec2,       
-    SAT_vec3,       
-    SAT_vec4,       
-    SAT_mat1x1,   
-    SAT_mat1x2,  
-    SAT_mat1x3, 
+
+  enum ShaderArgType {
+    SAT_scalar,
+    SAT_vec1,
+    SAT_vec2,
+    SAT_vec3,
+    SAT_vec4,
+    SAT_mat1x1,
+    SAT_mat1x2,
+    SAT_mat1x3,
     SAT_mat1x4,
     SAT_mat2x1,
-    SAT_mat2x2,   
-    SAT_mat2x3,  
-    SAT_mat2x4, 
-    SAT_mat3x1, 
-    SAT_mat3x2, 
-    SAT_mat3x3,   
-    SAT_mat3x4,  
-    SAT_mat4x1,  
-    SAT_mat4x2,  
-    SAT_mat4x3,  
+    SAT_mat2x2,
+    SAT_mat2x3,
+    SAT_mat2x4,
+    SAT_mat3x1,
+    SAT_mat3x2,
+    SAT_mat3x3,
+    SAT_mat3x4,
+    SAT_mat4x1,
+    SAT_mat4x2,
+    SAT_mat4x3,
     SAT_mat4x4,
     SAT_sampler1d,
     SAT_sampler2d,
@@ -231,20 +235,20 @@ public:
   };
 
   enum ShaderStateDep {
-    SSD_NONE          =  0,
-    SSD_general       =  1,
-    SSD_transform     =  2,
-    SSD_color         =  4,
-    SSD_colorscale    =  8,
-    SSD_material      = 16,
-    SSD_shaderinputs  = 32,
-    SSD_fog           = 64,
+    SSD_NONE          = 0x000,
+    SSD_general       = 0x001,
+    SSD_transform     = 0x002,
+    SSD_color         = 0x004,
+    SSD_colorscale    = 0x008,
+    SSD_material      = 0x010,
+    SSD_shaderinputs  = 0x020,
+    SSD_fog           = 0x040,
   };
 
   enum ShaderBug {
     SBUG_ati_draw_buffers,
   };
-  
+
   enum ShaderMatFunc {
     SMF_compose,
     SMF_transform_dlight,
@@ -252,36 +256,36 @@ public:
     SMF_transform_slight,
     SMF_first,
   };
- 
+
   struct ShaderArgId {
     string     _name;
     ShaderType _type;
     int        _seqno;
-  }; 
-  
-  struct ShaderArgInfo {  
+  };
+
+  struct ShaderArgInfo {
     ShaderArgId       _id;
     ShaderArgClass    _class;
     ShaderArgClass    _subclass;
-    ShaderArgType     _type;      
+    ShaderArgType     _type;
     ShaderArgDir      _direction;
     bool              _varying;
     NotifyCategory   *_cat;
   };
- 
+
   enum ShaderPtrType {
     SPT_float,
     SPT_double,
     SPT_unknown
-  };  
-  
+  };
+
   // Container structure for data of parameters ShaderPtrSpec.
   struct ShaderPtrData {
   private:
     PT(ReferenceCount) _pta;
 
   public:
-    void *_ptr; 
+    void *_ptr;
     ShaderPtrType _type;
     bool _updated;
     int _size; //number of elements vec3[4]=12
@@ -340,8 +344,8 @@ public:
     PT(InternalName)  _name;
     int               _append_uv;
   };
-  
-  struct ShaderPtrSpec { 
+
+  struct ShaderPtrSpec {
     ShaderArgId       _id;
     int               _dim[3]; //n_elements,rows,cols
     int               _dep[2];
@@ -377,8 +381,8 @@ public:
   public:
     INLINE ShaderFile() {};
     INLINE ShaderFile(const string &shared);
-    INLINE ShaderFile(const string &vertex, 
-                      const string &fragment, 
+    INLINE ShaderFile(const string &vertex,
+                      const string &fragment,
                       const string &geometry,
                       const string &tess_control,
                       const string &tess_evaluation);
@@ -405,18 +409,18 @@ public:
   void parse_upto(string &result, string pattern, bool include);
   void parse_rest(string &result);
   bool parse_eof();
-  
+
   void cp_report_error(ShaderArgInfo &arg, const string &msg);
   bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len);
   bool cp_errchk_parameter_in(ShaderArgInfo &arg);
-  bool cp_errchk_parameter_ptr(ShaderArgInfo &p); 
+  bool cp_errchk_parameter_ptr(ShaderArgInfo &p);
   bool cp_errchk_parameter_varying(ShaderArgInfo &arg);
   bool cp_errchk_parameter_uniform(ShaderArgInfo &arg);
   bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
   bool cp_errchk_parameter_sampler(ShaderArgInfo &arg);
   bool cp_parse_eol(ShaderArgInfo &arg,
                     vector_string &pieces, int &next);
-  bool cp_parse_delimiter(ShaderArgInfo &arg, 
+  bool cp_parse_delimiter(ShaderArgInfo &arg,
                           vector_string &pieces, int &next);
   string cp_parse_non_delimiter(vector_string &pieces, int &next);
   bool cp_parse_coord_sys(ShaderArgInfo &arg,
@@ -426,12 +430,12 @@ public:
   void cp_optimize_mat_spec(ShaderMatSpec &spec);
 
 #ifdef HAVE_CG
-  void cg_recurse_parameters(CGparameter parameter, 
-                          const ShaderType &type, 
+  void cg_recurse_parameters(CGparameter parameter,
+                          const ShaderType &type,
                           bool &success);
 #endif
-  
-  bool compile_parameter(const ShaderArgId        &arg_id, 
+
+  bool compile_parameter(const ShaderArgId        &arg_id,
                          const ShaderArgClass     &arg_class,
                          const ShaderArgClass     &arg_subclass,
                          const ShaderArgType      &arg_type,
@@ -444,7 +448,7 @@ public:
 
 #ifdef HAVE_CG
 private:
-  ShaderArgClass cg_parameter_class(CGparameter p); 
+  ShaderArgClass cg_parameter_class(CGparameter p);
   ShaderArgType cg_parameter_type(CGparameter p);
   ShaderArgDir cg_parameter_dir(CGparameter p);
 
@@ -456,7 +460,7 @@ private:
   bool cg_compile_shader(const ShaderCaps &caps);
   void cg_release_resources();
   void cg_report_errors();
-  
+
   // Determines the appropriate cg profile settings and stores them in the active shader caps
   // based on any profile settings stored in the shader's header
   void cg_get_profile_from_header(ShaderCaps &caps);
@@ -478,24 +482,24 @@ public:
   bool cg_compile_for(const ShaderCaps &caps, CGcontext &ctx,
                       CGprogram &vprogram, CGprogram &fprogram,
                       CGprogram &gprogram, pvector<CGparameter> &map);
-  
+
 #endif
 
 public:
-  pvector <ShaderPtrSpec> _ptr_spec; 
+  pvector <ShaderPtrSpec> _ptr_spec;
   epvector <ShaderMatSpec> _mat_spec;
   pvector <ShaderTexSpec> _tex_spec;
   pvector <ShaderVarSpec> _var_spec;
-  
+
   bool _error_flag;
   CPT(ShaderFile) _text;
 
 protected:
-  CPT(ShaderFile) _filename; 
+  CPT(ShaderFile) _filename;
   int _parse;
   bool _loaded;
   ShaderLanguage _language;
-  
+
   static ShaderCaps _default_caps;
   static ShaderUtilization _shader_utilization;
   static int _shaders_generated;
@@ -511,7 +515,7 @@ protected:
   typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts;
   Contexts _contexts;
 
-private:  
+private:
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
 
   Shader();

+ 1 - 1
panda/src/gobj/textureCollection.cxx

@@ -76,7 +76,7 @@ TextureCollection(PyObject *self, PyObject *sequence) {
     if (item == NULL) {
       return;
     }
-    PyObject *result = PyObject_CallMethod(self, (char *)"addTexture", (char *)"O", item);
+    PyObject *result = PyObject_CallMethod(self, (char *)"add_texture", (char *)"O", item);
     Py_DECREF(item);
     if (result == NULL) {
       // Unable to add item--probably it wasn't of the appropriate type.

+ 34 - 1
panda/src/gobj/textureStage.I

@@ -141,13 +141,46 @@ set_texcoord_name(const string &name) {
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureStage::get_texcoord_name
 //       Access: Published
-//  Description: Returns the InternalName
+//  Description: See set_texcoord_name.  The default is
+//               InternalName::get_texcoord().
 ////////////////////////////////////////////////////////////////////
 INLINE InternalName *TextureStage::
 get_texcoord_name() const {
   return _texcoord_name;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureStage::get_tangent_name
+//       Access: Published
+//  Description: Returns the set of tangents this texture stage will
+//               use.  This is the same as get_texcoord_name(),
+//               except that the first part is "tangent".
+////////////////////////////////////////////////////////////////////
+INLINE InternalName *TextureStage::
+get_tangent_name() const {
+  if (_texcoord_name->get_parent() == NULL) {
+    return InternalName::get_tangent();
+  } else {
+    return InternalName::get_tangent_name(_texcoord_name->get_basename());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureStage::get_binormal_name
+//       Access: Published
+//  Description: Returns the set of binormals this texture stage will
+//               use.  This is the same as get_binormal_name(),
+//               except that the first part is "binormal".
+////////////////////////////////////////////////////////////////////
+INLINE InternalName *TextureStage::
+get_binormal_name() const {
+  if (_texcoord_name->get_parent() == NULL) {
+    return InternalName::get_binormal();
+  } else {
+    return InternalName::get_binormal_name(_texcoord_name->get_basename());
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureStage::set_mode
 //       Access: Published

+ 0 - 3
panda/src/gobj/textureStage.cxx

@@ -154,9 +154,6 @@ compare_to(const TextureStage &other) const {
   if (get_tex_view_offset() != other.get_tex_view_offset()) {
     return get_tex_view_offset() < other.get_tex_view_offset() ? -1 : 1;
   }
-  if (get_mode() != other.get_mode()) {
-    return get_mode() < other.get_mode() ? -1 : 1;
-  }
   if (get_mode() == M_combine) {
     if (get_combine_rgb_mode() != other.get_combine_rgb_mode()) {
       return get_combine_rgb_mode() < other.get_combine_rgb_mode() ? -1 : 1;

+ 11 - 12
panda/src/gobj/textureStage.h

@@ -45,7 +45,7 @@ PUBLISHED:
 
   enum Mode {
     // Modes that pertain to the fixed-function pipeline.
-    
+
     M_modulate,
     M_decal,
     M_blend,
@@ -53,12 +53,12 @@ PUBLISHED:
     M_add,
     M_combine,
     M_blend_color_scale,
-    
+
     M_modulate_glow,  // When fixed-function, equivalent to modulate.
     M_modulate_gloss, // When fixed-function, equivalent to modulate.
-    
+
     // Modes that are only relevant to shader-based rendering.
-    
+
     M_normal,
     M_normal_height,
     M_glow,         // Rarely used: modulate_glow  is more efficient.
@@ -67,7 +67,7 @@ PUBLISHED:
     M_selector,
     M_normal_gloss,
   };
-  
+
   enum CombineMode {
     CM_undefined,
     CM_replace,
@@ -113,12 +113,14 @@ PUBLISHED:
   INLINE void set_texcoord_name(InternalName *name);
   INLINE void set_texcoord_name(const string &texcoord_name);
   INLINE InternalName *get_texcoord_name() const;
-  
+  INLINE InternalName *get_tangent_name() const;
+  INLINE InternalName *get_binormal_name() const;
+
   INLINE void set_mode(Mode mode);
   INLINE Mode get_mode() const;
-  
+
   INLINE bool is_fixed_function() const;
-  
+
   INLINE void set_color(const LColor &color);
   INLINE LColor get_color() const;
 
@@ -231,7 +233,7 @@ private:
 
   static PT(TextureStage) _default_stage;
   static UpdateSeq _sort_seq;
-  
+
 public:
   // Datagram stuff
   static void register_with_read_factory();
@@ -272,6 +274,3 @@ EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, TextureStage::CombineOperan
 #include "textureStage.I"
 
 #endif
-
-
-  

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